Imported Upstream version 2.02.98 upstream/1.02.77 upstream/2.02.98
authorAnas Nashif <anas.nashif@intel.com>
Tue, 5 Mar 2013 09:47:43 +0000 (01:47 -0800)
committerAnas Nashif <anas.nashif@intel.com>
Tue, 5 Mar 2013 09:47:43 +0000 (01:47 -0800)
622 files changed:
Makefile.in
README
VERSION
VERSION_DM
WHATS_NEW
WHATS_NEW_DM
aclocal.m4 [new file with mode: 0644]
autoconf/config.guess
autoconf/config.sub
configure
configure.in
daemons/Makefile.in
daemons/clvmd/Makefile.in
daemons/clvmd/clvm.h
daemons/clvmd/clvmd-cman.c
daemons/clvmd/clvmd-command.c
daemons/clvmd/clvmd-comms.h
daemons/clvmd/clvmd-corosync.c
daemons/clvmd/clvmd-gulm.c [deleted file]
daemons/clvmd/clvmd-gulm.h [deleted file]
daemons/clvmd/clvmd-openais.c
daemons/clvmd/clvmd-singlenode.c
daemons/clvmd/clvmd.c
daemons/clvmd/clvmd.h
daemons/clvmd/lvm-functions.c
daemons/clvmd/lvm-functions.h
daemons/clvmd/refresh_clvmd.c
daemons/clvmd/tcp-comms.c [deleted file]
daemons/clvmd/tcp-comms.h [deleted file]
daemons/cmirrord/clogd.c
daemons/cmirrord/cluster.c
daemons/cmirrord/functions.c
daemons/cmirrord/link_mon.c
daemons/cmirrord/local.c
daemons/dmeventd/.exported_symbols
daemons/dmeventd/Makefile.in
daemons/dmeventd/dmeventd.c
daemons/dmeventd/dmeventd.h
daemons/dmeventd/libdevmapper-event.c
daemons/dmeventd/libdevmapper-event.h
daemons/dmeventd/plugins/Makefile.in
daemons/dmeventd/plugins/lvm2/.exported_symbols
daemons/dmeventd/plugins/lvm2/Makefile.in
daemons/dmeventd/plugins/lvm2/dmeventd_lvm.c
daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h
daemons/dmeventd/plugins/mirror/Makefile.in
daemons/dmeventd/plugins/mirror/dmeventd_mirror.c
daemons/dmeventd/plugins/raid/.exported_symbols [new file with mode: 0644]
daemons/dmeventd/plugins/raid/Makefile.in [new file with mode: 0644]
daemons/dmeventd/plugins/raid/dmeventd_raid.c [new file with mode: 0644]
daemons/dmeventd/plugins/snapshot/Makefile.in
daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c
daemons/dmeventd/plugins/thin/.exported_symbols [new file with mode: 0644]
daemons/dmeventd/plugins/thin/Makefile.in [new file with mode: 0644]
daemons/dmeventd/plugins/thin/dmeventd_thin.c [new file with mode: 0644]
daemons/lvmetad/Makefile.in [new file with mode: 0644]
daemons/lvmetad/lvmetad-client.h [new file with mode: 0644]
daemons/lvmetad/lvmetad-core.c [new file with mode: 0644]
daemons/lvmetad/test.sh [new file with mode: 0755]
daemons/lvmetad/testclient.c [new file with mode: 0644]
doc/example.conf.in
doc/kernel/crypt.txt [new file with mode: 0644]
doc/kernel/delay.txt [new file with mode: 0644]
doc/kernel/flakey.txt [new file with mode: 0644]
doc/kernel/io.txt [new file with mode: 0644]
doc/kernel/kcopyd.txt [new file with mode: 0644]
doc/kernel/linear.txt [new file with mode: 0644]
doc/kernel/log.txt [new file with mode: 0644]
doc/kernel/persistent-data.txt [new file with mode: 0644]
doc/kernel/queue-length.txt [new file with mode: 0644]
doc/kernel/raid.txt [new file with mode: 0644]
doc/kernel/service-time.txt [new file with mode: 0644]
doc/kernel/snapshot.txt [new file with mode: 0644]
doc/kernel/striped.txt [new file with mode: 0644]
doc/kernel/thin-provisioning.txt [new file with mode: 0644]
doc/kernel/uevent.txt [new file with mode: 0644]
doc/kernel/verity.txt [new file with mode: 0644]
doc/kernel/zero.txt [new file with mode: 0644]
doc/lvm2-raid.txt [new file with mode: 0644]
doc/lvm_fault_handling.txt
doc/lvmetad_design.txt [new file with mode: 0644]
doc/tagging.txt
doc/udev_assembly.txt [new file with mode: 0644]
include/.symlinks.in
lib/Makefile.in
lib/activate/activate.c
lib/activate/activate.h
lib/activate/dev_manager.c
lib/activate/dev_manager.h
lib/activate/fs.c
lib/activate/fs.h
lib/cache/lvmcache.c
lib/cache/lvmcache.h
lib/cache/lvmetad.c [new file with mode: 0644]
lib/cache/lvmetad.h [new file with mode: 0644]
lib/commands/toolcontext.c
lib/commands/toolcontext.h
lib/config/config.c
lib/config/config.h
lib/config/defaults.h
lib/datastruct/btree.c
lib/datastruct/str_list.c
lib/datastruct/str_list.h
lib/device/dev-cache.c
lib/device/dev-cache.h
lib/device/dev-io.c
lib/device/dev-luks.c
lib/device/dev-md.c
lib/device/dev-swap.c
lib/device/device.c
lib/device/device.h
lib/display/display.c
lib/display/display.h
lib/error/errseg.c
lib/filters/device-types.h [new file with mode: 0644]
lib/filters/filter-composite.c
lib/filters/filter-md.c
lib/filters/filter-mpath.c [new file with mode: 0644]
lib/filters/filter-mpath.h [new file with mode: 0644]
lib/filters/filter-persistent.c
lib/filters/filter-persistent.h
lib/filters/filter-regex.c
lib/filters/filter-regex.h
lib/filters/filter-sysfs.c
lib/filters/filter.c
lib/filters/filter.h
lib/format1/disk-rep.c
lib/format1/format1.c
lib/format1/import-export.c
lib/format1/import-extents.c
lib/format1/layout.c
lib/format1/lvm1-label.c
lib/format1/vg_number.c
lib/format_pool/disk_rep.c
lib/format_pool/format_pool.c
lib/format_pool/import_export.c
lib/format_pool/pool_label.c
lib/format_text/archive.c
lib/format_text/archiver.c
lib/format_text/export.c
lib/format_text/flags.c
lib/format_text/format-text.c
lib/format_text/format-text.h
lib/format_text/import-export.h
lib/format_text/import.c
lib/format_text/import_vsn1.c
lib/format_text/layout.h
lib/format_text/tags.c
lib/format_text/text_export.h
lib/format_text/text_import.h
lib/format_text/text_label.c
lib/freeseg/freeseg.c
lib/label/label.c
lib/label/label.h
lib/locking/cluster_locking.c
lib/locking/external_locking.c
lib/locking/file_locking.c
lib/locking/locking.c
lib/locking/locking.h
lib/locking/locking_types.h
lib/locking/no_locking.c
lib/log/log.c
lib/log/log.h
lib/metadata/lv.c
lib/metadata/lv.h
lib/metadata/lv_alloc.h
lib/metadata/lv_manip.c
lib/metadata/merge.c
lib/metadata/metadata-exported.h
lib/metadata/metadata.c
lib/metadata/metadata.h
lib/metadata/mirror.c
lib/metadata/pv.c
lib/metadata/pv.h
lib/metadata/pv_alloc.h
lib/metadata/pv_manip.c
lib/metadata/pv_map.c
lib/metadata/pv_map.h
lib/metadata/raid_manip.c [new file with mode: 0644]
lib/metadata/replicator_manip.c
lib/metadata/segtype.h
lib/metadata/snapshot_manip.c
lib/metadata/thin_manip.c [new file with mode: 0644]
lib/metadata/vg.c
lib/metadata/vg.h
lib/mirror/mirrored.c
lib/misc/configure.h.in
lib/misc/crc.c
lib/misc/lvm-exec.c
lib/misc/lvm-exec.h
lib/misc/lvm-file.c
lib/misc/lvm-file.h
lib/misc/lvm-globals.c
lib/misc/lvm-globals.h
lib/misc/lvm-percent.h
lib/misc/lvm-string.c
lib/misc/lvm-string.h
lib/misc/lvm-wrappers.c
lib/misc/lvm-wrappers.h
lib/misc/sharedlib.c
lib/misc/timestamp.c
lib/misc/util.c [deleted file]
lib/misc/util.h
lib/mm/memlock.c
lib/mm/memlock.h
lib/raid/.exported_symbols [new file with mode: 0644]
lib/raid/Makefile.in [new file with mode: 0644]
lib/raid/raid.c [new file with mode: 0644]
lib/replicator/replicator.c
lib/report/columns.h
lib/report/properties.c
lib/report/properties.h
lib/report/report.c
lib/snapshot/snapshot.c
lib/striped/striped.c
lib/thin/.exported_symbols [new file with mode: 0644]
lib/thin/Makefile.in [new file with mode: 0644]
lib/thin/thin.c [new file with mode: 0644]
lib/unknown/unknown.c
lib/uuid/uuid.c
lib/zero/zero.c
libdaemon/Makefile.in [new file with mode: 0644]
libdaemon/client/Makefile.in [new file with mode: 0644]
libdaemon/client/config-util.c [new file with mode: 0644]
libdaemon/client/config-util.h [new file with mode: 0644]
libdaemon/client/daemon-client.c [new file with mode: 0644]
libdaemon/client/daemon-client.h [new file with mode: 0644]
libdaemon/client/daemon-io.c [new file with mode: 0644]
libdaemon/client/daemon-io.h [new file with mode: 0644]
libdaemon/server/Makefile.in [new file with mode: 0644]
libdaemon/server/daemon-log.c [new file with mode: 0644]
libdaemon/server/daemon-log.h [new file with mode: 0644]
libdaemon/server/daemon-server.c [new file with mode: 0644]
libdaemon/server/daemon-server.h [new file with mode: 0644]
libdm/Makefile.in
libdm/datastruct/hash.c
libdm/ioctl/libdm-compat.h [deleted file]
libdm/ioctl/libdm-iface.c
libdm/ioctl/libdm-targets.h
libdm/libdevmapper.h
libdm/libdm-common.c
libdm/libdm-common.h
libdm/libdm-config.c [new file with mode: 0644]
libdm/libdm-deptree.c
libdm/libdm-file.c
libdm/libdm-report.c
libdm/libdm-string.c
libdm/misc/dm-ioctl.h
libdm/misc/dm-log-userspace.h
libdm/mm/dbg_malloc.c
libdm/mm/dbg_malloc.h [deleted file]
libdm/mm/pool-debug.c
libdm/mm/pool-fast.c
libdm/mm/pool.c
libdm/regex/matcher.c
libdm/regex/ttree.c
liblvm/Makefile.in
liblvm/lvm2app.h
liblvm/lvm_base.c
liblvm/lvm_lv.c
liblvm/lvm_misc.c
liblvm/lvm_pv.c
liblvm/lvm_vg.c
make.tmpl.in
man/Makefile.in
man/blkdeactivate.8.in [new file with mode: 0644]
man/clvmd.8.in
man/dmeventd.8.in
man/dmsetup.8.in
man/fsadm.8.in
man/lvchange.8.in
man/lvconvert.8.in
man/lvcreate.8.in
man/lvdisplay.8.in
man/lvextend.8.in
man/lvm.8.in
man/lvm.conf.5.in
man/lvmchange.8.in
man/lvmconf.8.in
man/lvmdiskscan.8.in
man/lvmdump.8.in
man/lvmetad.8.in [new file with mode: 0644]
man/lvmsadc.8.in
man/lvmsar.8.in
man/lvreduce.8.in
man/lvremove.8.in
man/lvrename.8.in
man/lvresize.8.in
man/lvs.8.in
man/lvscan.8.in
man/pvchange.8.in
man/pvck.8.in
man/pvcreate.8.in
man/pvdisplay.8.in
man/pvmove.8.in
man/pvremove.8.in
man/pvresize.8.in
man/pvs.8.in
man/pvscan.8.in
man/vgcfgbackup.8.in
man/vgcfgrestore.8.in
man/vgchange.8.in
man/vgck.8.in
man/vgconvert.8.in
man/vgcreate.8.in
man/vgdisplay.8.in
man/vgexport.8.in
man/vgextend.8.in
man/vgimport.8.in
man/vgimportclone.8.in
man/vgmerge.8.in
man/vgmknodes.8.in
man/vgreduce.8.in
man/vgremove.8.in
man/vgrename.8.in
man/vgs.8.in
man/vgscan.8.in
man/vgsplit.8.in
packaging/device-mapper.changes [deleted file]
packaging/device-mapper.spec [deleted file]
python/Makefile.in [new file with mode: 0644]
python/example.py [new file with mode: 0644]
python/liblvm.c [new file with mode: 0644]
python/setup.py.in [new file with mode: 0644]
scripts/Makefile.in
scripts/blk_availability_init_red_hat.in [new file with mode: 0644]
scripts/blk_availability_systemd_red_hat.service.in [new file with mode: 0644]
scripts/blkdeactivate.sh.in [new file with mode: 0644]
scripts/clvmd_init_red_hat.in
scripts/cmirrord_init_red_hat.in
scripts/dm_event_systemd_red_hat.service.in [new file with mode: 0644]
scripts/dm_event_systemd_red_hat.socket.in [new file with mode: 0644]
scripts/fsadm.sh [changed mode: 0644->0755]
scripts/gdbinit [new file with mode: 0644]
scripts/last_cvs_update.sh [deleted file]
scripts/lvm2_activation_generator_systemd_red_hat.c [new file with mode: 0644]
scripts/lvm2_lvmetad_init_red_hat.in [new file with mode: 0644]
scripts/lvm2_lvmetad_systemd_red_hat.service.in [new file with mode: 0644]
scripts/lvm2_lvmetad_systemd_red_hat.socket.in [new file with mode: 0644]
scripts/lvm2_monitoring_init_red_hat.in
scripts/lvm2_monitoring_init_rhel4
scripts/lvm2_monitoring_systemd_red_hat.service.in [new file with mode: 0644]
scripts/lvm2_tmpfiles_red_hat.conf.in [new file with mode: 0644]
scripts/lvm2create_initrd/lvm2create_initrd
scripts/lvm2create_initrd/lvm2create_initrd.8
scripts/lvm2create_initrd/lvm2create_initrd.pod
scripts/lvm2create_initrd/lvm2udev
scripts/lvmdump.sh
scripts/vgimportclone.sh
test/.gitignore [deleted file]
test/Makefile.in
test/api/Makefile.in
test/api/lvtest.c [new file with mode: 0644]
test/api/lvtest.sh [new file with mode: 0644]
test/api/pe_start.c [new file with mode: 0644]
test/api/pe_start.sh [new file with mode: 0644]
test/api/percent.c
test/api/percent.sh
test/api/test.c
test/api/thin_percent.c [new file with mode: 0644]
test/api/thin_percent.sh [new file with mode: 0644]
test/api/vgtest.sh
test/check.sh [deleted file]
test/harness.c [deleted file]
test/harness.sh [deleted file]
test/lib/aux.sh [new file with mode: 0644]
test/lib/check.sh [new file with mode: 0644]
test/lib/get.sh [new file with mode: 0644]
test/lib/harness.c [new file with mode: 0644]
test/lib/lvm-wrapper.sh [new file with mode: 0644]
test/lib/not.c [new file with mode: 0644]
test/lib/test.sh [new file with mode: 0644]
test/lib/utils.sh [new file with mode: 0644]
test/lvm-utils.sh [deleted file]
test/mkdtemp [deleted file]
test/not.c [deleted file]
test/shell/000-basic.sh [new file with mode: 0644]
test/shell/activate-minor.sh [new file with mode: 0644]
test/shell/activate-missing-segment.sh [new file with mode: 0644]
test/shell/activate-missing.sh [new file with mode: 0644]
test/shell/activate-partial.sh [new file with mode: 0644]
test/shell/clvmd-restart.sh [new file with mode: 0644]
test/shell/covercmd.sh [new file with mode: 0644]
test/shell/discards-thin.sh [new file with mode: 0644]
test/shell/dmeventd-restart.sh [new file with mode: 0644]
test/shell/dumpconfig.sh [new file with mode: 0644]
test/shell/fsadm.sh [new file with mode: 0644]
test/shell/inconsistent-metadata.sh [new file with mode: 0644]
test/shell/listings.sh [new file with mode: 0644]
test/shell/lock-blocking.sh [new file with mode: 0644]
test/shell/lvchange-mirror.sh [new file with mode: 0644]
test/shell/lvchange-partial.sh [new file with mode: 0644]
test/shell/lvconvert-mirror-basic-0.sh [new file with mode: 0644]
test/shell/lvconvert-mirror-basic-1.sh [new file with mode: 0644]
test/shell/lvconvert-mirror-basic-2.sh [new file with mode: 0644]
test/shell/lvconvert-mirror-basic-3.sh [new file with mode: 0644]
test/shell/lvconvert-mirror-basic.sh [new file with mode: 0644]
test/shell/lvconvert-mirror.sh [new file with mode: 0644]
test/shell/lvconvert-raid.sh [new file with mode: 0644]
test/shell/lvconvert-raid10.sh [new file with mode: 0644]
test/shell/lvconvert-repair-dmeventd.sh [new file with mode: 0644]
test/shell/lvconvert-repair-policy.sh [new file with mode: 0644]
test/shell/lvconvert-repair-replace.sh [new file with mode: 0644]
test/shell/lvconvert-repair-snapshot.sh [new file with mode: 0644]
test/shell/lvconvert-repair-transient-dmeventd.sh [new file with mode: 0644]
test/shell/lvconvert-repair-transient.sh [new file with mode: 0644]
test/shell/lvconvert-repair.sh [new file with mode: 0644]
test/shell/lvconvert-thin.sh [new file with mode: 0644]
test/shell/lvconvert-twostep.sh [new file with mode: 0644]
test/shell/lvcreate-large-raid.sh [new file with mode: 0644]
test/shell/lvcreate-large-raid10.sh [new file with mode: 0644]
test/shell/lvcreate-large.sh [new file with mode: 0644]
test/shell/lvcreate-mirror.sh [new file with mode: 0644]
test/shell/lvcreate-operation.sh [new file with mode: 0644]
test/shell/lvcreate-pvtags.sh [new file with mode: 0644]
test/shell/lvcreate-raid.sh [new file with mode: 0644]
test/shell/lvcreate-raid10.sh [new file with mode: 0644]
test/shell/lvcreate-repair.sh [new file with mode: 0644]
test/shell/lvcreate-small-snap.sh [new file with mode: 0644]
test/shell/lvcreate-striped-mirror.sh [new file with mode: 0644]
test/shell/lvcreate-thin-power2.sh [new file with mode: 0644]
test/shell/lvcreate-thin-snap.sh [new file with mode: 0644]
test/shell/lvcreate-thin.sh [new file with mode: 0644]
test/shell/lvcreate-usage.sh [new file with mode: 0644]
test/shell/lvextend-percent-extents.sh [new file with mode: 0644]
test/shell/lvextend-snapshot-dmeventd.sh [new file with mode: 0644]
test/shell/lvextend-snapshot-policy.sh [new file with mode: 0644]
test/shell/lvm-init.sh [new file with mode: 0644]
test/shell/lvmcache-exercise.sh [new file with mode: 0644]
test/shell/lvmetad-disabled.sh [new file with mode: 0644]
test/shell/lvmetad-dump.sh [new file with mode: 0644]
test/shell/lvmetad-lvm1.sh [new file with mode: 0644]
test/shell/lvmetad-pvs.sh [new file with mode: 0644]
test/shell/lvmetad-pvscan-cache.sh [new file with mode: 0644]
test/shell/lvmetad-restart.sh [new file with mode: 0644]
test/shell/lvmetad-test.sh [new file with mode: 0644]
test/shell/lvmetad-warning.sh [new file with mode: 0644]
test/shell/lvresize-mirror.sh [new file with mode: 0644]
test/shell/lvresize-raid.sh [new file with mode: 0644]
test/shell/lvresize-raid10.sh [new file with mode: 0644]
test/shell/lvresize-rounding.sh [new file with mode: 0644]
test/shell/lvresize-usage.sh [new file with mode: 0644]
test/shell/mdata-strings.sh [new file with mode: 0644]
test/shell/metadata-balance.sh [new file with mode: 0644]
test/shell/metadata-dirs.sh [new file with mode: 0644]
test/shell/metadata.sh [new file with mode: 0644]
test/shell/mirror-names.sh [new file with mode: 0644]
test/shell/mirror-vgreduce-removemissing.sh [new file with mode: 0644]
test/shell/name-mangling.sh [new file with mode: 0644]
test/shell/nomda-missing.sh [new file with mode: 0644]
test/shell/pool-labels.sh [new file with mode: 0644]
test/shell/pv-duplicate.sh [new file with mode: 0644]
test/shell/pv-min-size.sh [new file with mode: 0644]
test/shell/pv-range-overflow.sh [new file with mode: 0644]
test/shell/pvchange-usage.sh [new file with mode: 0644]
test/shell/pvcreate-metadata0.sh [new file with mode: 0644]
test/shell/pvcreate-operation-md.sh [new file with mode: 0644]
test/shell/pvcreate-operation.sh [new file with mode: 0644]
test/shell/pvcreate-usage.sh [new file with mode: 0644]
test/shell/pvmove-basic.sh [new file with mode: 0644]
test/shell/pvremove-usage.sh [new file with mode: 0644]
test/shell/read-ahead.sh [new file with mode: 0644]
test/shell/snapshot-autoumount-dmeventd.sh [new file with mode: 0644]
test/shell/snapshot-merge.sh [new file with mode: 0644]
test/shell/snapshots-of-mirrors.sh [new file with mode: 0644]
test/shell/tags.sh [new file with mode: 0644]
test/shell/test-partition.sh [new file with mode: 0644]
test/shell/thin-autoumount-dmeventd.sh [new file with mode: 0644]
test/shell/topology-support.sh [new file with mode: 0644]
test/shell/unknown-segment.sh [new file with mode: 0644]
test/shell/unlost-pv.sh [new file with mode: 0644]
test/shell/vgcfgbackup-usage.sh [new file with mode: 0644]
test/shell/vgchange-maxlv.sh [new file with mode: 0644]
test/shell/vgchange-partial.sh [new file with mode: 0644]
test/shell/vgchange-sysinit.sh [new file with mode: 0644]
test/shell/vgchange-usage.sh [new file with mode: 0644]
test/shell/vgcreate-usage.sh [new file with mode: 0644]
test/shell/vgextend-restoremissing.sh [new file with mode: 0644]
test/shell/vgextend-usage.sh [new file with mode: 0644]
test/shell/vgimportclone.sh [new file with mode: 0644]
test/shell/vgmerge-operation.sh [new file with mode: 0644]
test/shell/vgmerge-usage.sh [new file with mode: 0644]
test/shell/vgreduce-removemissing-snapshot.sh [new file with mode: 0644]
test/shell/vgreduce-usage.sh [new file with mode: 0644]
test/shell/vgrename-usage.sh [new file with mode: 0644]
test/shell/vgsplit-operation.sh [new file with mode: 0644]
test/shell/vgsplit-stacked.sh [new file with mode: 0644]
test/shell/vgsplit-usage.sh [new file with mode: 0644]
test/t-000-basic.sh [deleted file]
test/t-activate-missing.sh [deleted file]
test/t-activate-partial.sh [deleted file]
test/t-covercmd.sh [deleted file]
test/t-dmeventd-restart.sh [deleted file]
test/t-fsadm.sh [deleted file]
test/t-inconsistent-metadata.sh [deleted file]
test/t-listings.sh [deleted file]
test/t-lock-blocking.sh [deleted file]
test/t-lvchange-mirror.sh [deleted file]
test/t-lvconvert-mirror-basic-0.sh [deleted file]
test/t-lvconvert-mirror-basic-1.sh [deleted file]
test/t-lvconvert-mirror-basic-2.sh [deleted file]
test/t-lvconvert-mirror-basic-3.sh [deleted file]
test/t-lvconvert-mirror-basic.sh [deleted file]
test/t-lvconvert-mirror.sh [deleted file]
test/t-lvconvert-repair-dmeventd.sh [deleted file]
test/t-lvconvert-repair-policy.sh [deleted file]
test/t-lvconvert-repair-replace.sh [deleted file]
test/t-lvconvert-repair-transient.sh [deleted file]
test/t-lvconvert-repair.sh [deleted file]
test/t-lvconvert-twostep.sh [deleted file]
test/t-lvcreate-mirror.sh [deleted file]
test/t-lvcreate-operation.sh [deleted file]
test/t-lvcreate-pvtags.sh [deleted file]
test/t-lvcreate-small-snap.sh [deleted file]
test/t-lvcreate-usage.sh [deleted file]
test/t-lvextend-percent-extents.sh [deleted file]
test/t-lvextend-snapshot-dmeventd.sh [deleted file]
test/t-lvextend-snapshot-policy.sh [deleted file]
test/t-lvm-init.sh [deleted file]
test/t-lvmcache-exercise.sh [deleted file]
test/t-lvresize-mirror.sh [deleted file]
test/t-lvresize-usage.sh [deleted file]
test/t-mdata-strings.sh [deleted file]
test/t-metadata-balance.sh [deleted file]
test/t-metadata.sh [deleted file]
test/t-mirror-names.sh [deleted file]
test/t-mirror-vgreduce-removemissing.sh [deleted file]
test/t-nomda-missing.sh [deleted file]
test/t-pool-labels.sh [deleted file]
test/t-pv-range-overflow.sh [deleted file]
test/t-pvchange-usage.sh [deleted file]
test/t-pvcreate-metadata0.sh [deleted file]
test/t-pvcreate-operation-md.sh [deleted file]
test/t-pvcreate-operation.sh [deleted file]
test/t-pvcreate-usage.sh [deleted file]
test/t-pvmove-basic.sh [deleted file]
test/t-pvremove-usage.sh [deleted file]
test/t-read-ahead.sh [deleted file]
test/t-snapshot-autoumount-dmeventd.sh [deleted file]
test/t-snapshot-merge.sh [deleted file]
test/t-snapshots-of-mirrors.sh [deleted file]
test/t-tags.sh [deleted file]
test/t-test-partition.sh [deleted file]
test/t-topology-support.sh [deleted file]
test/t-unknown-segment.sh [deleted file]
test/t-unlost-pv.sh [deleted file]
test/t-vgcfgbackup-usage.sh [deleted file]
test/t-vgchange-maxlv.sh [deleted file]
test/t-vgchange-usage.sh [deleted file]
test/t-vgcreate-usage.sh [deleted file]
test/t-vgextend-restoremissing.sh [deleted file]
test/t-vgextend-usage.sh [deleted file]
test/t-vgmerge-operation.sh [deleted file]
test/t-vgmerge-usage.sh [deleted file]
test/t-vgreduce-usage.sh [deleted file]
test/t-vgrename-usage.sh [deleted file]
test/t-vgsplit-operation.sh [deleted file]
test/t-vgsplit-stacked.sh [deleted file]
test/t-vgsplit-usage.sh [deleted file]
test/test-utils.sh [deleted file]
test/unit/Makefile.in [new file with mode: 0644]
test/unit/bitset_t.c [new file with mode: 0644]
test/unit/config_t.c [new file with mode: 0644]
test/unit/matcher_data.h [new file with mode: 0644]
test/unit/matcher_t.c [new file with mode: 0644]
test/unit/run.c [new file with mode: 0644]
test/unit/string_t.c [new file with mode: 0644]
tools/Makefile.in
tools/args.h
tools/commands.h
tools/dmsetup.c
tools/dumpconfig.c
tools/lvchange.c
tools/lvconvert.c
tools/lvcreate.c
tools/lvm.c
tools/lvm2cmd.h
tools/lvmcmdlib.c
tools/lvmcmdline.c
tools/lvmdiskscan.c
tools/lvremove.c
tools/lvrename.c
tools/lvresize.c
tools/lvscan.c
tools/polldaemon.c
tools/polldaemon.h
tools/pvchange.c
tools/pvck.c
tools/pvcreate.c
tools/pvdisplay.c
tools/pvmove.c
tools/pvremove.c
tools/pvresize.c
tools/pvscan.c
tools/reporter.c
tools/toollib.c
tools/toollib.h
tools/tools.h
tools/vgcfgbackup.c
tools/vgcfgrestore.c
tools/vgchange.c
tools/vgconvert.c
tools/vgcreate.c
tools/vgexport.c
tools/vgextend.c
tools/vgimport.c
tools/vgmerge.c
tools/vgreduce.c
tools/vgremove.c
tools/vgrename.c
tools/vgscan.c
tools/vgsplit.c
udev/10-dm.rules.in
udev/11-dm-lvm.rules [deleted file]
udev/11-dm-lvm.rules.in [new file with mode: 0644]
udev/13-dm-disk.rules [deleted file]
udev/13-dm-disk.rules.in [new file with mode: 0644]
udev/69-dm-lvm-metad.rules.in [new file with mode: 0644]
udev/95-dm-notify.rules [deleted file]
udev/95-dm-notify.rules.in [new file with mode: 0644]
udev/Makefile.in
unit-tests/mm/pool_valgrind_t.c

index f7e34f4bb9228040ee801c9ecd909765339718c2..4d39577400a880b65fb3806b082aa94605e1f65e 100644 (file)
@@ -16,7 +16,7 @@ srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 top_builddir = @top_builddir@
 
-SUBDIRS = doc include man scripts
+SUBDIRS = doc include man
 
 ifeq ("@UDEV_RULES@", "yes")
   SUBDIRS += udev
@@ -26,16 +26,25 @@ ifeq ("@INTL@", "yes")
   SUBDIRS += po
 endif
 
-SUBDIRS += lib tools daemons libdm
+SUBDIRS += lib tools daemons libdm libdaemon
 
 ifeq ("@APPLIB@", "yes")
   SUBDIRS += liblvm
 endif
 
+ifeq ("@PYTHON_BINDINGS@", "yes")
+  SUBDIRS += python
+endif
+
+SUBDIRS += scripts
+
+# FIXME Should use intermediate Makefiles here!
 ifeq ($(MAKECMDGOALS),distclean)
-  SUBDIRS = doc include man scripts \
-    lib tools daemons libdm \
-    udev po liblvm test/api test
+  SUBDIRS = doc include man test scripts \
+    libdaemon lib tools daemons libdm \
+    udev po liblvm python \
+    unit-tests/datastruct unit-tests/mm unit-tests/regex
+tools.distclean: test.distclean
 endif
 DISTCLEAN_DIRS += lcov_reports*
 DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl
@@ -43,11 +52,12 @@ DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl
 include make.tmpl
 
 libdm: include
-lib: libdm
+lib: libdm libdaemon
 liblvm: lib
-daemons: lib tools
-tools: lib device-mapper
+daemons: lib libdaemon tools
+tools: lib libdaemon device-mapper
 po: tools daemons
+scripts: liblvm libdm
 
 lib.device-mapper: include.device-mapper
 libdm.device-mapper: include.device-mapper
@@ -64,6 +74,10 @@ po.pofile: tools.pofile daemons.pofile
 pofile: po.pofile
 endif
 
+ifeq ("@PYTHON_BINDINGS@", "yes")
+python: liblvm
+endif
+
 ifneq ("$(CFLOW_CMD)", "")
 tools.cflow: libdm.cflow lib.cflow
 daemons.cflow: tools.cflow
@@ -77,7 +91,7 @@ all: cscope.out
 endif
 DISTCLEAN_TARGETS += cscope.out
 
-check check_cluster check_local: all
+check check_cluster check_local check_lvmetad unit: all
        $(MAKE) -C test $(@)
 
 install_system_dirs:
@@ -92,6 +106,20 @@ install_system_dirs:
 install_initscripts: 
        $(MAKE) -C scripts install_initscripts
 
+install_systemd_generators:
+       $(MAKE) -C scripts install_systemd_generators
+
+install_systemd_units:
+       $(MAKE) -C scripts install_systemd_units
+
+ifeq ("@PYTHON_BINDINGS@", "yes")
+install_python_bindings:
+       $(MAKE) -C liblvm/python install_python_bindings
+endif
+
+install_tmpfiles_configuration:
+       $(MAKE) -C scripts install_tmpfiles_configuration
+
 LCOV_TRACES = libdm.info lib.info tools.info \
        daemons/dmeventd.info daemons/clvmd.info
 CLEAN_TARGETS += $(LCOV_TRACES)
@@ -111,11 +139,10 @@ lcov-reset:
 
 # maybe use subdirs processing to create tracefiles...
 $(LCOV_TRACES):
-       $(LCOV) -b $(top_srcdir)/$(basename $@) \
-               -d $(basename $@) -c -o - | $(SED) \
+       $(LCOV) -b $(basename $@) -d $(basename $@) \
+               --ignore-errors source -c -o - | $(SED) \
                -e "s/\(dmeventd_lvm.[ch]\)/plugins\/lvm2\/\1/" \
-               -e "s/\(dmeventd_mirror.c\)/plugins\/mirror\/\1/" \
-               -e "s/\(dmeventd_snapshot.c\)/plugins\/snapshot\/\1/" \
+               -e "s/dmeventd_\(mirror\|snapshot\|thin\|raid\)\.c/plugins\/\1\/dmeventd_\1\.c/" \
                >$@
 
 ifneq ("$(GENHTML)", "")
@@ -135,9 +162,10 @@ ifeq ("$(TESTING)", "yes")
 # testing and report generation
 RUBY=ruby1.9 -Ireport-generators/lib -Ireport-generators/test
 
-.PHONEY: unit-test ruby-test test-programs
+.PHONY: unit-test ruby-test test-programs
 
 # FIXME: put dependencies on libdm and liblvm
+# FIXME: Should be handled by Makefiles in subdirs, not here at top level.
 test-programs:
        cd unit-tests/regex && $(MAKE)
        cd unit-tests/datastruct && $(MAKE)
diff --git a/README b/README
index bd6214cd12020945ed9927c3e953bbdc78633e23..6a7e11c3ee9069be556d4e580d38097e7734e4fc 100644 (file)
--- a/README
+++ b/README
@@ -8,20 +8,26 @@ There is no warranty - see COPYING and COPYING.LIB.
 Tarballs are available from:
   ftp://sources.redhat.com/pub/lvm2/
 
-To access the CVS tree use:
-  cvs -d :pserver:cvs@sources.redhat.com:/cvs/lvm2 login
-  CVS password: cvs
-  cvs -d :pserver:cvs@sources.redhat.com:/cvs/lvm2 co LVM2
+The source code is stored in git:
+  http://git.fedorahosted.org/git/lvm2.git
+  git clone git://git.fedorahosted.org/git/lvm2.git
 
 Mailing list for general discussion related to LVM2:
   linux-lvm@redhat.com
   Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm
 
-Mailing list for LVM2 development, patches and commits:
+Mailing lists for LVM2 development, patches and commits:
   lvm-devel@redhat.com
   Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm
 
+  lvm2-commits@lists.fedorahosted.org (Read-only archive of commits)
+  Subscribe from https://fedorahosted.org/mailman/listinfo/lvm2-commits
+
 Mailing list for device-mapper development, including kernel patches
 and multipath-tools:
   dm-devel@redhat.com
   Subscribe from https://www.redhat.com/mailman/listinfo/dm-devel
+
+The source code repository used until 7th June 2012 is accessible here:
+  http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/?cvsroot=lvm2.
+
diff --git a/VERSION b/VERSION
index f8dbace8e361f4175baaac3f571dcc196a18123f..88723319c15b132a5d844cd4091d4b6ed891c5dc 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.02.79(2) (2010-12-20)
+2.02.98(2) (2012-10-15)
index 859320745bf930ceba72c967236467421b149dee..79221b6b9cc2d49254833c95da1f656ac996951e 100644 (file)
@@ -1 +1 @@
-1.02.60 (2010-12-20)
+1.02.77 (2012-10-15)
index 08cc26c39ffe2d72f57b5f0bd7dbd601e8a30801..c0ae3dfaae79e58bc30730e716f591efcec665ec 100644 (file)
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,8 +1,703 @@
+Version 2.02.98 - 15th October 2012
+===================================
+  Switch from DEBUG() to DEBUGLOG() in lvmetad as -DDEBUG is already used.
+  Prohibit not yet supported change of thin-pool to read-only.
+  Support creation of read-only thin volumes (lvcreate -p r).
+  Using autoextend percent 0 for thin pool fails 'lvextend --use-policies'.
+  Introduce blkdeactivate script to deactivate block devs with dependencies.
+  Implement devices/global_filter to hide devices from lvmetad.
+  Make vgscan --cache an alias for pvscan --cache.
+  Clear lvmetad metadata/PV cache before a rescan.
+  Fix a segmentation fault upon receiving a corrupt lvmetad response.
+  Give inconsistent metadata warnings in pvscan --cache.
+  Make lvremove ask before discarding data areas.
+  Avoid overlapping locks that could cause a deadlock in lvmetad.
+  Fix memory leaks in libdaemon and lvmetad.
+  Optimize libdaemon logging for a fast no-output path.
+  Only create lvmetad pidfile when running as a daemon (no -f).
+  Warn if lvmetad is running but disabled.
+  Warn about running lvmetad with use_lvmetad = 0 in example.conf.
+  Update lvmetad help output (flags and their meaning).
+  Make pvscan --cache read metadata from LVM1 PVs.
+  Make libdaemon buffer handling asymptotically more efficient.
+  Add lvmdump -l, to collect a state dump from lvmetad.
+  Make --sysinit suppress lvmetad connection failure warnings.
+  Prohibit usage of lvcreate --thinpool with --mirrors.
+  Fix lvm2api origin reporting for thin snapshot volume.
+  Add configure --enable-python_bindings for liblvm2app to new python subdir.
+  Add implementation of lvm2api function lvm_percent_to_float.
+  Allow non power of 2 thin chunk sizes if thin pool driver supports that.
+  Allow limited metadata changes when PVs are missing via [vg|lv]change.
+  Do not start dmeventd for lvchange --resync when monitoring is off.
+  Remove pvscan --cache from lvm2-lvmetad init script.
+  Remove ExecStartPost with pvscan --cache from lvm2-lvmetad.service.
+  Report invalid percentage for property snap_percent of non-snaphot LVs.
+  Disallow conversion of thin LVs to mirrors.
+  Fix lvm2api data_percent reporting for thin volumes.
+  Do not allow RAID LVs in a clustered volume group.
+  Add --discards to lvconvert.
+  Add --poolmetadata to lvconvert and support thin meta/data dev stacking.
+  Support changes of permissions for thin snapshot volumes.
+  Enhance insert_layer_for_lv() with recursive rename for _tdata LVs.
+  Skip building dm tree for thin pool when called with origin_only flag.
+  Add internal lv_rename_update() to rename LV without updating mda.
+  Ensure descriptors 0,1,2 are always available, using /dev/null if necessary.
+  Use /proc/self/fd when available for closing opened descriptors efficiently.
+  Add missing pkg init with --enable-testing in configure.in (2.02.71).
+  Fix inability to create, extend or convert to a large (> 1TiB) RAID LV.
+  Split out daemon-io from daemon-shared and always build libdaemonclient.
+  Update lvmetad communications to cope with clients using different filters.
+  Add (p)artial attribute to lvs.
+  Don't try to issue discards to a missing PV to avoid segfault.
+  Clear LV_NOSYNCED flag when a RAID1 LV is converted to a linear LV.
+  Disallow RAID1 upconvert if the LV was created with --nosync.
+  Depend on systemd-udev-settle in units generated by activation generator.
+  Fix vgchange -aay not to activate non-matching LVs that follow a matching LV.
+  Fix lvchange --resync for RAID LVs which had no effect.
+  Restructure mirror resync code.
+  Disallow addition of RAID images until the array is in-sync.
+  Fix RAID LV creation with '--test' so valid commands do not fail.
+  Add lvm_lv_rename() to lvm2api.
+  Fix setvbuf code by closing and reopening stream before changing buffer.
+  Disable private buffering when using liblvm.
+  When private stdin/stdout buffering is not used always use silent mode.
+  Add log/silent to lvm.conf equivalent to -qq.
+  Suppress non-essential stdout with -qq.
+  Switch non-essential log_print messages to log_print_unless_silent.
+  Use -q as short form of --quiet.
+  Add RAID10 support (--type raid10).
+  Reuse _reload_lv() in more lvconvert functions.
+  Fix 32-bit device size arithmetic needing 64-bit casting throughout tree.
+  Remove numerous unnecessary #includes and the empty util.c.
+  Fix dereference of NULL in lvmetad error path logging.
+  Fix buffer memory leak in lvmetad logging.
+  Add support for lvcreate --discards.
+  Correct the discards field in the lvs manpage (2.02.97).
+  Use proper condition to check for discards settings unsupported by kernel.
+  Reinstate correct default to ignore discards for thin metadata from old tools.
+  Issue error message when -i and -m args do not match specified RAID type.
+  Change lvmetad logging syntax from -ddd to -l {all|wire|debug}.
+  Add new libdaemon logging infrastructure.
+
+Version 2.02.97 - 7th August 2012
+=================================
+  Improve documention of allocation policies in lvm.8.
+  Increase limit for major:minor to 4095:1048575 when using -My option.
+  Add make install_systemd_generators.
+  Add generator for lvm2 activation systemd units.
+  Add lvm_config_find_bool lvm2app fn to retrieve bool value from config tree.
+  Respect --test when using lvmetad.
+  No longer capitalise first LV attribute char for invalid snapshots.
+  Allow vgextend to add PVs to a VG that is missing PVs.
+  Recognise Micron PCIe SSDs in filter and move array out to device-types.h.
+  Fix dumpconfig <node> to print only <node> without its siblings. (2.02.89)
+  Do not issue "Failed to handle a client connection" error if lvmetad killed.
+  Support lvchange --discards and -Z with thin pools.
+  Add discard LV segment field to reports.
+  Add --discards to lvcreate --thin.
+  Set discard and external snapshot features if thin pool target is vsn 1.1+.
+  Count percentage of completeness upwards not downwards when merging snapshot.
+  Skip activation when using vg/lvchange --sysinit -a ay and lvmetad is active.
+  Fix extending RAID 4/5/6 logical volumes
+  Fix test for PV with unknown VG in process_each_pv to ignore ignored mdas.
+  Update man pages with --activate ay option and auto_activation_volume_list.
+  Fix _alloc_parallel_area to avoid picking already-full areas for raid devices.
+  Use vgchange -aay instead of vgchange -ay in clmvd init script.
+  Add activation/auto_activation_volume_list to lvm.conf.
+  Add --activate ay to lvcreate, lvchange, pvscan and vgchange.
+  Add support for volume autoactivation using lvmetad.
+  Add --activate synonym for --available arg and prefer --activate.
+  Never issue discards when LV extents are being reconfigured, not deleted.
+  Allow release_lv_segment_area to fail as functions it calls can fail.
+  Open device read-only instead of read-write when obtaining readahead value.
+  Fix lvconvert thin pool error path NULL pointer dereference.
+  Detect create_instance() failure in pvscan_lvmetad_single().
+  Use 64-bit calculations for reserved memory and stack.
+  Fix missing sync of filesystem when creating thin volume snapshot.
+
+Version 2.02.96 - 8th June 2012
+===============================
+  Upstream source repo now fedorahosted.org git not sources.redhat.com CVS.
+  Fix error paths for regex filter initialization.
+  Re-enable partial activation of non-thin LVs until it can be fixed. (2.02.90)
+  Fix alloc cling to cling to PVs already found with contiguous policy.
+  Fix cling policy not to behave like normal policy if no previous LV seg.
+  Fix allocation loop not to use later policies when --alloc cling without tags.
+  Append _TO_LVSEG to names of internal A_CONTIGUOUS and A_CLING flags.
+  Add missing pkg init --with-systemdsystemunitdir in configure.in (2.02.92).
+  Fix division by zero if PV with zero PE count is used during vgcfgrestore.
+  Add initial support for thin pool lvconvert.
+  Fix lvrename for thin volumes (regression in for_each_sub_lv). (2.02.89)
+  Fix up-convert when mirror activation is controlled by volume_list and tags.
+  Warn of deadlock risk when using snapshots of mirror segment type.
+  Fix bug in cmirror that caused incorrect status info to print on some nodes.
+  Remove statement that snapshots cannot be tagged from lvm man page.
+  Disallow changing cluster attribute of VG while RAID LVs are active.
+  Fix lvconvert error message for non-mergeable volumes.
+  Allow subset of failed devices to be replaced in RAID LVs.
+  Prevent resume from creating error devices that already exist from suspend.
+  Improve clmvd singlenode locking for better testing.
+  Update and correct lvs man page with supported column names.
+  Handle replacement of an active device that goes missing with an error device.
+  Change change raid1 segtype always to request a flush when suspending.
+  Add udev info and context to lvmdump.
+  Add lvmetad man page.
+  Fix RAID device replacement code so that it works under snapshot.
+  Fix inability to split RAID1 image while specifying a particular PV.
+  Update man pages to give them all the same look&feel.
+  Fix lvresize of thin pool for striped devices.
+  For lvresize round upward when specifying number of extents.
+  For lvcreate with %FREE support rounding downward stripe alignment.
+  Change message severity to log_very_verbose for missing dev info in udev db.
+  Fix lvconvert when specifying removal of a RAID device other than last one.
+  Fix ability to handle failures in mirrored log in dmeventd plugin. (2.02.89)
+  Fix unlocking volume group in vgreduce in error path.
+  Cope when VG name is part of the supplied name in lvconvert --splitmirrors -n.
+  Fix exclusive lvchange running from other node. (2.02.89)
+  Add 'vgscan --cache' functionality for consistency with 'pvscan --cache'.
+  Keep exclusive activation in pvmove if LV is already active.
+  Disallow exclusive pvmove if some affected LVs are not exclusively activated.
+  Remove unused and wrongly set cluster VG flag from clvmd lock query command.
+  Fix pvmove for exclusively activated LV pvmove in clustered VG. (2.02.86)
+  Always free hash table on update_pvid_to_vgid() in lvmetad.
+  Update and fix monitoring of thin pool devices.
+  Check hash insert success in lock_vg in clvmd.
+  Check for buffer overwrite in get_cluster_type() in clvmd.
+  Fix global/detect_internal_vg_cache_corruption config check.
+  Update lcov Makefile target to support all dmeventd plugins.
+  Fix initializiation of thin monitoring. (2.02.92)
+  Cope with improperly formatted device numbers in /proc/devices. (2.02.91)
+  Exit if LISTEN_PID environment variable incorrect in lvmetad systemd handover.
+  Use pvscan --cache instead of vgscan in lvmetad scripts.
+  Fix fsadm propagation of -e option.
+  Fix fsadm parsing of /proc/mounts files (don't check for substrings).
+  Fix fsadm usage of arguments with space.
+  Fix arg_int_value alongside ARG_GROUPABLE --major/--minor for lvcreate/change.
+  Fix name conflicts that prevent down-converting RAID1 when specifying a device
+  Improve thin_check option passing and use configured path.
+  Add --with-thin-check configure option for path to thin_check.
+  Fix error message when pvmove LV activation fails with name already in use.
+  Better structure layout for device_info in dev_subsystem_name().
+  Change message severity for creation of VG over uninitialised devices.
+  Fix error path for failed toolcontext creation.
+  Detect lvm binary path in lvmetad udev rules.
+  Don't unlink socket on lvmetad shutdown if instantiated from systemd.
+  Restart lvmetad automatically from systemd if it exits from uncaught signal.
+  Fix warn msg for thin pool chunk size and update man for chunksize. (2.02.89)
+
+Version 2.02.95 - 6th March 2012
+================================
+  If unspecified, adjust thin pool metadata and chunk size to fit into 128MB.
+  Print just warning on thin pool check callback path for failing check.
+  Always use 64bit arithmetic with VG extent_size expression.
+  Validate udev structures in _insert_udev_dir().
+  Take repeatable --major --minor with pvscan --cache instead of major:minor.
+  Scan all devices for lvmetad if 'pvscan --cache' used without device list.
+  Populate lvmcache from lvmetad before displaying PVs in pvscan. (2.02.94)
+  Suppress incorrect -n pvscan warning now always displayed. (2.02.94)
+
+Version 2.02.94 - 3rd March 2012
+================================
+  Add support to execute thin_check with each de/active of thin pool.
+  Fix automatic estimation of metadata device size for thin pool.
+  Test for alloc fail from _alloc_pv_segment() in _extend_pv().
+  Check for alloc fail from get_segtype_from_string() in _lvcreate_params().
+  Add _rimage as reserved suffix to lvm.8 man page.
+  Improve error logging from mpath filter.
+  Check for allocation failure in hold_lock() in clvmd.
+  Use set_lv() (wipe initial 4KiB) for non zeroed thin volume.
+  Allow cluster mirrors to handle the absence of the checkpoint lib (libSaCkpt).
+  Revert free of allocated segtype in init segment error path (2.02.89).
+  Test dm_hash_insert() failures in filter-persistent.c and fid_add_mda().
+  Ensure clvmd message is always NUL-terminated after read.
+  Add some close() and dev_close() error path backtraces.
+  Set stdin/stdout/stderr to /dev/null for polldaemon.
+  Limit the max size of processed clvmd message to ~8KB.
+  Do not send uninitialised bytes in cluster error reply messages.
+  Use unsigned type for bitmask instead of enum type for lvm properties.
+  Add missing cleanup of excl_uuid hash on some exit paths of clvmd.
+  Check for existence of vg_name in _format1/_pool_vg_read().
+  Fix missing break in _format_pvsegs (2.02.92).
+  Test seg pointer for non-null it in raid_target_percent error path.
+  Check for errors in _init_tags() during config loading.
+  Always check result of _set_vg_name() in lvcreate.
+  Drop unused call to uname() during clvmd initialization.
+  Test allocation result in sysfs filter creation.
+  Limit sscanf parameters with buffer size in clvmd get_initial_state().
+  Use const lv pointer for lv_is_active...() functions. 
+  Use same signed numbers in _mirrored_transient_status().
+  Support 'pvscan --cache' to update lvmetad state from specific PVs.
+  Provide new metadata daemon for testing with configure --enable-lvmetad .
+  Integrate client-side lvmetad into build.
+
+Version 2.02.93 - 23rd February 2012
+====================================
+  Require number of stripes to be greater than parity devices in higher RAID.
+  Fix allocation code to allow replacement of single RAID 4/5/6 device.
+  Check all tags and LV names are in a valid form in vg_validate.
+  Add tmpfiles.d style configuration for lvm2 lock and run directory.
+  Add configure --with-tmpfilesdir for dir holding volatile-file configuration.
+  Allow 'lvconvert --repair' to operate on RAID 4/5/6.
+  Fix build_parallel_areas_from_lv to account correctly for raid parity devices.
+  Print message when faulty raid devices have been replaced.
+
+Version 2.02.92 - 20th February 2012
+====================================
+  Read dmeventd monitoring config settings for every lvm command.
+  For thin devices, initialize monitoring only for thin pools not thin volumes.
+  Make conversion from a synced 'mirror' to 'raid1' not cause a full resync.
+  Properly test buffer for unit check in units_to_bytes().
+  Add configure --with-systemdsystemunitdir.
+  Add check for allocation failure in _build_matcher().
+  Add check for rimage name allocation failure in _raid_add_images().
+  Add check for mda_copy failure in _text_pv_setup().
+  Add check for _mirrored_init_target failure.
+  Add free_orphan_vg.
+  Skip pv/vg_set_fid processing if the fid is same.
+  Check for foreach loop errors in _vg_read_orphans() (2.02.91).
+  Clean error paths for format instance creation (2.02.91).
+  Release vg in error path of _format1_vg_read() instead of just free().
+  Report allocation failure for allocation of PV structure.
+  Add clvmd init dependency on dlm service when running with new corosync.
+
+Version 2.02.91 - 12th February 2012
+====================================
+  Remove PV-based format instances (which are no longer needed).
+  Link all orphan PVs directly to a per-format global orphan VG.
+  Refactor lvmcache around an internal API.
+  Stop processing lvextend if trying to extend a mirror that is being recovered.
+  Add pool_below_threshold() function to check thin pool percent status.
+  Fix test for snap percent for failing merge when removing LV.
+  Switch int to void return for str_list_del().
+  Fix error path handling in _build_desc().
+  Add range test for device number in _scan_proc_dev().
+  Use signed long for sysconf() call in cmirrord.
+  Do not write in front of log buffer in print_log().
+  Add boundary test for number of mirror devs and logs.
+  Check that whole locking_dir fits _lock_dir buffer in init_file_locking().
+  Use list functions for label_exit().
+  Ensure strncpy() function always ends with '\0'.
+  Set status in _fsadm_cmd() for error path.
+  Add missing deps for lvm2api for rebuild when lvm-internal is changed.
+  Fix resource leaks for failing allocation of formats (lvm1/2,pool).
+  Release allocated resources in error path for composite_filter_create().
+  Do not use lstat() results when failed in _rm_link().
+  Remove a "waiting for another thread" log message from dmeventd plugins.
+
+Version 2.02.90 - 1st February 2012
+===================================
+  sync_local_dev_names before (re)activating mirror log for initialisation.
+  Disable partial activation for thin LVs and LVs with all missing segments.
+  Do not print warning for pv_min_size between 512KB and 2MB.
+  Clean up systemd unit ordering and requirements.
+  Fix lcov reports when srcdir != builddir.
+  Allow ALLOC_NORMAL to track reserved extents for log and data on same PV.
+  Automatically detect whether corosync clvmd needs to use confdb or cmap.
+  Fix data% report for thin volume used as origin for non-thin snapshot.
+
+Version 2.02.89 - 26th January 2012
+===================================
+  Add missing check for uname result in clvmd TEST processing.
+  Fix memleak in target_version() error path (unsupported LIST_VERSIONS).
+  Limit data_alignment and data_alignment_offset to 32bit values.
+  Check for correctness of uint64 dev_size value in format_text.
+  Thin pools have segment fields thin_count, zero, transaction_id.
+  Add data_percent and metadata_percent for thin pools to lvs -v.
+  Add data_lv & metadata_lv fields to lvs for thin pools.
+  Add data_percent & pool_lv fields to lvs for thin volumes.
+  Rename origin_only parm to use_layer for lv_info and use with thin LVs.
+  Add lv_thin_pool_transaction_id to read the transaction_id value.
+  Use {suspend,resume}_origin_only when up-converting RAID, as mirrors do.
+  Always add RAID metadata LVs to deptree (even when origin_only is set).
+  Change exclusive LV activation logic to try local node before remote nodes.
+  Add CLVMD_FLAG_REMOTE to skip processing on local node.
+  Prompt if request is made to remove a snapshot whose "Merge failed".
+  Allow removal of an invalid snapshot that was to be merged on next activation.
+  Don't allow a user to merge an invalid snapshot.
+  Use m and M lv_attr to indicate that a snapshot merge failed in lvs.
+  Differentiate between snapshot status of "Invalid" and "Merge failed".
+  Report snapshot usage percent of origin volume when a snapshot is merging.
+  Require global/lvdisplay_shows_full_device_path for (bogus) lvm1-style paths.
+  Do not report linear segtype for non-striped targets.
+  Record creation host & time for each LV and report as lv_time & lv_host.
+  Make error message hit when preallocated memlock memory exceeded clearer.
+  Use R lv_attr to indicate read-only activation of non-read-only device in lvs.
+  Show read-only activation override in lvdisplay & add 4 to perms in -c.
+  Add activation/read_only_volume_list to override LV permission in metadata.
+  Give priority to emcpower devices with duplicate PVIDs.
+  Add check for error in _adjust_policy_params() (lvextend --use-policies).
+  Round specified percentages upwards (%LV, %VG...) when resizing LVs.
+  Use dmeventd_lvm2_command in dmeventd plugins snapshot, raid, mirror.
+  Add helper dmeventd_lvm2_command() to libdevmapper-event-lvm2 library.
+  Update documentation for dmeventd.
+  Remove unnecessary stat before opening device in dev_open_flags.
+  Reduce number of lstat calls when selecting device alias.
+  Add _dev_init to initialize common struct device members.
+  Always zalloc struct device during initialization.
+  Fix missing thread list manipulation protection in dmeventd.
+  Do not derefence lv pointer in _percent_run() function before NULL check.
+  Allow empty strings for description and creation_host config fields.
+  Issue deprecation warning when removing last lvm1-format snapshot.
+  Reinstate support for snapshot removal with lvm1 format. (2.02.86)
+  Add policy-based automated repair of RAID logical volumes.
+  Don't allow two images to be split and tracked from a RAID LV at one time.
+  Don't allow size change of RAID LV that is tracking changes for a split image.
+  Don't allow size change of RAID sub-LVs independently.
+  Don't allow name change of RAID LV that is tracking changes for a split image.
+  Do not allow users to change the name of RAID sub-LVs independently.
+  Do not allow users to change permissions on RAID sub-LVs.
+  Allow lvconvert to replace specified devices in a RAID array.
+  Add activation/use_linear_target enabled by default.
+  Use gcc warning options only with .c to .o compilation.
+  Move y/n prompts to stderr and repeat if response has both 'n' and 'y'.
+  Replace the unit testing framework with CUnit (--enable-testing).
+  Fix dmeventd snapshot monitoring when multiple extensions were involved.
+  Don't ignore configure --mandir and --infodir.
+  Drop pool memory allocated within lv_has_target_type().
+  Reduce stack allocation of some PATH_MAX sized char buffers.
+  Unlock memory before writing metadata.
+  Add query before removing snapshots when inactive snapshot origin is removed.
+  Allow changing availability state of snapshots.
+  Skip non-virtual snapshots for availability change for lvchange with vg name.
+  Skip adjusting mirror region size unless mirror or raid.
+  Reorder prompt conditions for removal of active volumes.
+  Avoid 'mda inconsistency' by properly registering UNLABELLED_PV flag.(2.02.86)
+  Fix --enable-static_link unless using --enable-dmeventd / --enable-udev_sync.
+  Move gentoo MAKEDEV to /sbin in lvm2create_initrd.
+  Add filter to avoid scan of device if it is part of active multipath.
+  Add missing default $LVM_VG_NAME usage for snapshots.
+  Avoid extent_count overflow with lvextend.
+  Add missing lvrename mirrored log recursion in for_each_sub_lv.
+  Improve lv_extend stack reporting.
+  Increase virtual segment size instead of creating multiple segment list.
+  Add last_seg(lv) internal function.
+  Support empty string for log/prefix.
+  Disallow mirrored logs for cluster mirrors. (2.02.72)
+  Don't print char type[8] as a plain string in pvck PV type.
+  Use vg memory pool implicitly for vg read.
+  Always use vg memory pool for allocated lv segment.
+  Remove extra 4kB buffer allocated on stack in print_log().
+  Make move_lv_segment non-static function and use dm_list function.
+  Pass exclusive LV locks to all nodes in the cluster.
+  Improve lvcreate chunksize man page description.
+  Improve man page style for lvcreate & lvs.
+  Avoid recursive calls to dmeventd in its LVM plugins.
+  Log dev name now returned to kernel for registering during cmirror CTR.
+  Fix lv_info open_count test for disabled verify_udev_operations. (2.02.86)
+  Simplify code for lvm worker thread in clvmd.                     
+  Use pthread_barrier to synchronize clvmd threads at startup.
+  Limit clvmd's thread size to 128KiB and ignore activation/reserved_stack.
+  Reduce default preallocated stack size to 64KiB.
+  Add check for access through NULL pointer when refresh_filter() fails.
+  Use pthread condition for SINGLENODE lock implementation.
+  Improve backtrace reporting for some dev_manager_ functions.
+  Change message severity to log_warn when symlink creation fails.
+  Add ability to convert mirror segtype to RAID1 segtype.
+  Add ability to convert from linear to RAID1.
+  Add ability to extend mirrors with '--nosync' option.
+  Fix splitmirror LV names to maintain consistent state in a cluster.
+  Apply appropriate udev flags when suspending/resuming mirror sub-LVs.
+  Fix vgsplit to handle mirrored logs.
+  Clarify multi-name device filter pattern matching explanation in lvm.conf.
+  Introduce revert_lv for better pvmove cleanup.
+  Replace incomplete pvmove activation failure recovery code with a message.
+  Abort if _finish_pvmove suspend_lvs fails instead of cleaning up incompletely.
+  Change suspend_lvs to call vg_revert internally.
+  Change vg_revert to void and remove superfluous calls after failed vg_commit.
+  Use execvp for CLVMD restart to preserve environment settings.
+  Restart CLVMD with same cluster manager.
+  Fix log_error() usage in raid and unknown segtype initialisation.
+  Improve testing Makefile.
+  Fix install_ocf make target when srcdir != builddir. (2.02.80)
+  Support env vars LVM_CLVMD_BINARY and LVM_BINARY in clvmd.
+  Fix restart of clvmd (preserve exlusive locks). (2.02.64)
+  Add 'Volume Type' lv_attr characters for RAID and RAID_IMAGE.
+  Add activation/retry_deactivation to lvm.conf to retry deactivation of an LV.
+  Replace open_count check with holders/mounted_fs check on lvremove path.
+  Disallow the creation of mirrors (mirror or raid1 segtype) with only one leg.
+  Cleanup restart clvmd code (no memory allocation, debug print passed args).
+  Add all exclusive locks to clvmd restart option args.
+  Always send the whole clvmd packet header in refresh commands.
+  Add missing error checks for some system calls in cmirrord.
+  Add missing log_error() to lvresize command when fsadm tool fails.
+  Add support for DM_DEV_DIR device path into fsadm script.
+  Support different PATH setting for fsadm script testing.
+  Surround all executed commands with quotes in fsadm script.
+  Fix missing '$' in test for content of "$LVM" in fsadm script.
+  Move debug message in exec_cmd after sync_local_dev_names.
+  Fix clvmd processing of invalid request on local socket.
+  Fix command line option decoding.
+  Reset LV status when unlinking LV from VG.
+  Fix overly-strict extent-count divisibility requirements for striped mirrors.
+  Fix rounding direction in lvresize when reducing volume size.
+  Fix possible overflow of size if %FREE or %VG is used.
+  Fix vgchange activation of snapshot with virtual origin.
+  Activate virtual snapshot origin exclusively (only on local node in cluster).
+  Fix lv_mirror_count to handle mirrored stripes properly.
+  Fix failure to down-convert a mirror to linear due to udev "dev open" conflict
+  Fix mirrored log creation when PE size is small: use log_size >= region_size.
+  Fix log size calculation when only a log is being added to a mirror.
+  Add 7th lv_attr char to show the related kernel target.
+  Terminate pv_attr field correctly. (2.02.86)
+  Fix 'not not' typo in pvcreate man page.
+  Improve man page style for fsadm, lvreduce, lvremove, lvrename & lvresize.
+  Support break for vgchange and vgrefresh operation.
+  Switch int to unsigned type for pvmetadatacopies for pv_create().
+  Replace :space: with [\t ] for awk in vgimportclone (not widely supported).
+  Begin using 64-bit status field flags.
+  Detect sscanf recovering_region input error in cmirrord pull_state().
+  Fix error path bitmap leak in cmirrord import_checkpoint().
+  Log unlink() error in cmirrord remove_lockfile().
+  Remove incorrect requirement for -j or -m from lvchange error message.
+  Fix unsafe table load when splitting off smaller mirror from a larger one.
+  Use size_t return type for text_vg_export_raw() and export_vg_to_buffer().
+  Add configure --enable-lvmetad for building the (experimental) LVMetaD.
+  Fix resource leak when strdup fails in _get_device_status() (2.02.85).
+  Directly allocate buffer memory in a pvck scan instead of using a mempool.
+  Add configure --with-thin for segtypes "thin" and "thin_pool".
+  Fix raid shared lib segtype registration (2.02.87).
+
+Version 2.02.88 - 19th August 2011
+==================================
+  Remove incorrect 'Breaking' error message from allocation code. (2.02.87)
+  Add lvconvert --merge support for raid1 devices split with --trackchanges.
+  Support lvconvert of -m1 raid1 devices to a higher number.
+  Add --trackchanges support to lvconvert --splitmirrors option for raid1.
+  Support splitting off a single raid1 rimage in lvconvert --splitmirrors.
+  Use sync_local_dev_names when reducing number of raid rimages in lvconvert.
+  Add -V as short form of --virtualsize in lvcreate.
+  Fix make clean not to remove Makefile.  (2.02.87)
+
+Version 2.02.87 - 12th August 2011
+==================================
+  Fix make distclean to remove stray dmeventd and exported symbols files.
+  Add global/detect_internal_vg_cache_corruption to lvm.conf.
+  Use memory pool locking to check for corruption of internal VG structs.
+  Cache and share generated VG structs.
+  Fix possible format instance memory leaks and premature releases in _vg_read.
+  Suppress locking error messages in monitoring init scripts.
+  If pipe in clvmd fails return busy instead of using uninitialised descriptors.
+  Add ability to reduce the number of mirrors in raid1 arrays to lvconvert.
+  Add dmeventd plugin for raid.
+  Replace free_vg with release_vg and move it to vg.c.
+  Remove INCONSISTENT_VG flag from the code.
+  Remove lock from cache in _lock_vol even if unlock fails.
+  Initialise clvmd locks before lvm context to avoid open descriptor leaks.
+  Remove obsolete gulm clvmd cluster locking support.
+  Suppress low-level locking errors and warnings while using --sysinit.
+  Remove unused inconsistent_seqno variable in _vg_read().
+  Remove meaningless const type qualifiers on cast type.
+  Add test for fcntl error in singlenode client code.
+  Remove --force option from lvrename manpage.
+  Add global/mirror_segtype_default to pick md raid or dm mirror as default.
+  Add configure --with-raid for new segtype 'raid' for MD RAID 1/4/5/6 support.
+  Change DEFAULT_UDEV_SYNC to 1 so udev_sync is used if there is no config file.
+  Add systemd unit file to provide lvm2 monitoring.
+  Compare file size (as well as timestamp) to detect changed config file.
+
+Version 2.02.86 - 8th July 2011
+===============================
+  Remove unnecessary warning in pvcreate for MD linear devices.
+  Move snapshot removal activation logic into lib/activate.
+  Cope with a PV only discovered missing when creating deptree.
+  Abort operation if dm_tree_node_add_target_area fails.
+  Add activation/checks to lvm.conf to perform additional ioctl validation.
+  Always preload on suspend, even if no metadata changed (lvchange --refresh).
+  When suspending, automatically preload newly-visible existing LVs.
+  Teardown any stray devices with $COMMON_PREFIX during test runs.
+  Reinstate correct permissions when creating mirrors. [2.02.85]
+  Append 'm' attribute to pv_attr for missing PVs.
+  Annotate CLVMD_CMD_SYNC_NAMES in decode_cmd.
+  Remove enforcement of udev verification when using non-standard /dev location.
+  Keep an exclusive mirror non-clustered if reloaded e.g. during conversion.
+  Reject allocation if number of extents is not divisible by area count.
+  Fix cluster mirror creation to work with new mirror allocation algorithm.
+  Ignore activation/verify_udev_operations if dm kernel driver vsn < 4.18.
+  Add activation/verify_udev_operations to lvm.conf, disabled by default.
+  Call vg_mark_partial_lvs() before VG structure is returned from the cache.
+  Remove unused internal flag ACTIVATE_EXCL from the code.
+  Remove useless test of ACTIVATE_EXCL in lv_add_mirrors() clustered code path.
+  Add lv_activate_opts structure for activation (replacing activation flags).
+  Ignore inconsistent pre-commit metadata on MISSING_PV devs while activating.
+  Add proper udev library context initialization and finalization to liblvm.
+  Fix last snapshot removal to avoid table reload while a device is suspended.
+  Use dm_get_suspended_counter in replacement critical_section logic.
+  Downgrade critical_section errors to debug level until it is moved to libdm.
+  Fix ignored background polling default in vgchange -ay.
+  Fix pvmove activation sequences to avoid trapped I/O with multiple LVs.
+  Annotate critical section debug messages.
+  Fix reduction of mirrors with striped segments to always align to stripe size.
+  Validate mirror segments size.
+  Include lvmetad development code in tree.
+  Fix extent rounding for striped volumes never to reduce more than requested.
+  Fix create_temp_name to replace any '/' found in the hostname with '?'.
+  Always use append to file in lvmdump. selinux policy may ban file truncation.
+  Propagate test mode to clvmd to skip activation and changes to held locks.
+  Defer writing PV labels until vg_write.
+  Store label_sector only in struct physical_volume.
+  Permit --available with lvcreate so non-snapshot LVs need not be activated.
+  Report sector containing label in verbose message.
+  Clarify error message when unable to convert an LV into a snapshot of an LV.
+  Add and use dev_open_readonly and variations.
+  Do not log a superfluous stack message when the lv is properly processed.
+  Do not issue an error message when unable to remove .cache on read-only fs.
+  Avoid memlock size mismatch by preallocating stdio line buffers.
+  Rewrite vgreduce --removemissing --force to share lvconvert code.
+  Reorganize lvconvert --repair code to allow reuse.
+
+Version 2.02.85 - 29th April 2011
+=================================
+  Add new obtain_device_list_from_udev setting to lvm.conf.
+  Obtain device list from udev by default if LVM2 is compiled with udev support.
+  Add test for vgimportclone and querying of vgnames with duplicate pvs.
+  Avoid use of released memory when duplicate PV is found.
+  Add "devices/issue_discards" to lvm.conf.
+  Issue discards on lvremove and lvreduce etc. if enabled and supported.
+  Add seg_pe_ranges and devices fields to liblvm.
+  Fix incorrect tests for dm_snprintf() failure.
+  Fix some unmatching sign comparation gcc warnings in the code.
+  Support lv_extend() on empty LVs.
+  Avoid regenerating cache content when exported VG buffer is unchanged.
+  Extend the set of memory regions that are not locked to memory.
+  Workaround some problems when compiled for valgrind memcheck.
+  Support controlled quit of the lvm_thread_fn function in clvmd.
+  Fix reading of unallocated memory in lvm1 format import function.
+  Replace several strncmp() calls with id_equal().
+  Fix lvmcache_info transfer to orphan_vginfo in _lvmcache_update_vgname().
+  Fix -Wold-style-definition gcc warnings.
+  Rename MIRROR_NOTSYNCED to LV_NOTSYNCED.
+  Fix _move_lv_segments to handle empty LVs.
+  Fixes for lvconvert (including --repair) of temporary mirror stacks.
+  Avoid potential loop when removing mirror images.
+  Fix mirror removal always to take account of preferences as to which.
+  Fix MIRRORED flag usage.
+  Remove error messages issued by device_is_usable when run as non-root.
+  Add missing \0 for grown debug object in _bitset_with_random_bits().
+  Fix allocation of system_id buffer in volume_group structure.
+  Fix readlink usage inside get_primary_dev().
+  Use format instance mempool where possible and adequate.
+  Call destroy_instance for any PVs found in VG structure during vg_free call.
+  Add new free_pv_fid fn and use it throughout to free all attached fids.
+  Use only vg_set_fid and new pv_set_fid fn to assign the format instance.
+  Make create_text_context fn static and move it inside create_instance fn.
+  Add mem and ref_count fields to struct format_instance for own mempool use.
+  Use new alloc_fid fn for common format instance initialisation.
+  Optimise _get_token() and _eat_space().
+  Add _lv_postorder_vg() to improve efficiency for all LVs in VG.
+  Add gdbinit script for debugging.
+  Use hash tables to speedup string search in vg_validate().
+  Refactor allocation of VG structure adding alloc_vg().
+  Avoid possible endless loop in _free_vginfo when 4 or more VGs have same name.
+  Use empty string instead of /dev// for LV path when there's no VG.
+  Don't allocate unused VG mempool in _pvsegs_sub_single.
+  Do not send uninitialised bytes in local clvmd messages.
+  Support --help option for clvmd and return error for unknown option.
+  Avoid reading freed memory when printing LV segment type.
+  Fix syslog initialisation in clvmd to respect lvm.conf setting.
+  Fix possible overflow in maximum stripe size and physical extent size.
+  Improve pvremove error message when PV belongs to a VG.
+  Extend normal policy to allow mirror logs on same PVs as images if necessary.
+  Improve cling policy to recognise PVs already used during the transaction.
+  Improve normal allocation algorithm to include clinging to existing areas.
+  Add allocation/maximise_cling & mirror_logs_require_separate_pvs to lvm.conf.
+  Adapt metadata balancing code to work with metadata handling changes.
+  Add old_id field to physical_volume and fix pvchange -u for recent changes.
+  Allow pvresize on a PV with two metadata areas.
+  Change pvcreate to use new metadata handling interface.
+  Restructure existing pv_setup and pv_write and add pv_initialise.
+  Add internal interface to support adding and removing metadata areas.
+  Allow internal indexing of metadata areas (PV id + mda order).
+  Generalise internal format_instance infrastrusture for PV and VG use.
+  Handle decimal digits with --units instead of ignoring them silently.
+  Fix remaining warnings and compile with -Wpointer-arith.
+  Fix gcc warnings for unused variables and const casts.
+  Add stack backtraces for error paths in process_each_lv().
+  Temporarily suppress error from calling yes_no_prompt while locks are held.
+  Replace void* with char* arithmetic in _text_write, _text_read & send_message.
+  Fix compilation without DEVMAPPER_SUPPORT.
+  Remove fs_unlock() from lv_suspend error path.
+  Allow memory to stay locked between leaving and re-entering critical sections.
+  Rename memlock to critical_section throughout.
+  Make pv_min_size configurable and increase to 2048KB to exclude floppy drives.
+  Add find_config_tree_int64 to read 64-bit ints from config.
+  Ensure resuming exclusive cluster mirror continues to use local mirror target.
+  Clear temporary postorder LV status flags to allow re-use with same LV struct.
+  Remove invalid snapshot umount mesg which floods syslog from dmeventd plugin.
+  Add extended examples to pvmove man page.
+  Support LVM_TEST_DEVDIR env var for private /dev during testing.
+
+Version 2.02.84 - 9th February 2011
+===================================
+  Fix CRC32 calculation on big endian CPU (2.02.75).
+
+Version 2.02.83 - 4th February 2011
+===================================
+  Allow exclusive activation of snapshots in a cluster.
+  Leave EX lock unchanged when suspending a device in clvmd.
+  Use sync_dev_names in unlock_vg macro for cluster-wide dev name sync.
+  Fix fs operation stack handling when multiple operations on same device.
+  Increase hash table size to 1024 lv names and 64 pv uuids.
+  Remove fs_unlock() from lv_resume path.
+  Fix wipe size when setting up mda.
+  Remove unneeded checks for open_count in lv_info().
+  Synchronize with udev before checking open_count in lv_info().
+  Allow CLVMD_CMD_SYNC_NAMES to be propagated around the cluster if requested.
+  Add "dmsetup ls --tree" output to lvmdump.
+  Fix udev synchronization with no-locking --sysinit (2.02.80).
+  Improve man page style consistency for pvcreate, pvremove, pvresize, pvscan.
+  Avoid rebuilding of uuid validation table.
+  Improve lvcreate error text from insufficient "extents" to "free space".
+  Always use O_DIRECT when opening block devices to check for partitioning.
+
+Version 2.02.82 - 24th January 2011
+===================================
+  Bring lvscan man page up-to-date.
+  Fix lvchange --test to exit cleanly.
+  Add change_tag to toollib.
+  Allow multiple pvchange command line options to be specified together.
+  Do not fail pvmove polling if another process cleaned up first.
+  Avoid clvmd incrementing dlm lockspace reference count more than once.
+  Add -f (don't fork) option to clvmd and fix clvmd -d<num> description.
+
+Version 2.02.81 - 17th January 2011
+===================================
+  Do not scan devices in dev_reset_error_count().
+  Skip unnecessary LOCK_NULL unlock call during volume deactivation.
+  Skip fs_unlock when calling exec_cmd within activation code (for modprobe).
+  Extend exec_cmd params to specify when device sync (fs_unlock) is needed.
+  Replace fs_unlock by sync_local_dev_names to notify local clvmd. (2.02.80)
+  Introduce sync_local_dev_names and CLVMD_CMD_SYNC_NAMES to issue fs_unlock.
+  Accept fusion fio in device type filter.
+  Add ability to convert mirror log type from disk to mirrored.
+
+Version 2.02.80 - 10th January 2011
+===================================
+  Use same dm cookie for consecutive dm ops in same VG to reduce udev waits.
+  Speed up command processing by caching resolved config tree.
+  Pass config_tree to renamed function import_vg_from_config_tree().
+  Detect NULL handle in get_property().
+  Fix superfluous /usr in ocf_scriptdir instalation path.
+  Add --with-ocfdir configurable option.
+  Add aclocal.m4 (for pkgconfig).
+  Fix memory leak in persistent filter creation error path.
+  Check for errors setting up dm_task struct in _setup_task().
+  Fail polldaemon creation when lvmcache_init() fails.
+  Return PERCENT_INVALID for errors in _copy_percent() and _snap_percent().
+  Remove some unused variables.
+  Improve general lvconvert man page description.
+  Return 0 from cmirrord initscript 'start' if daemon is already running.
+  Fix wrongly paired unlocking of VG_GLOBAL in pvchange. (2.02.66)
+  Add backtraces for backup and backup_remove fail paths.
+  Detect errors from dm_task_set calls in _get_device_info (dmeventd).
+  Add backtraces for archive and backup_locally in check_current_backup().
+  Fix memory leak in debug mode of restart_clvmd() error path.
+  Log error message for pthread_join() failure in clvmd.
+
 Version 2.02.79 - 20th December 2010
 ====================================
   Remove some unused variables.
   Add missing test for reallocation error in _find_parallel_space().
-  Add checks for allocation errors in config node clonning.
+  Add checks for allocation errors in config node cloning.
   Fix error path if regex engine cannot be created in _build_matcher().
   Use char* arithmetic in target_version(), _process_all() & _targets().
   Fixing const cast gcc warnings in the code.
@@ -198,7 +893,7 @@ Version 2.02.73 - 18th August 2010
   Fix const warning in dev_manager_info() and _dev_manager_lv_rmnodes().
   Fix const warning in archive_file structure from archive.c.
   Clean generated files .exported_symbols_generated, example.conf for distclean.
-  Handle failure of all mirrored log devices and all but one mirror leg. 
+  Handle failure of all mirrored log devices and all but one mirror leg.
   Disallow 'mirrored' log type for cluster mirrors.
   Do not use VPATH in include/Makefile.
   Fix exported_symbols generation to use standard compiler arguments.
index c6ce2e6e561d06ff2915fb5152a3214339186a96..2d0b05c0a172296b07867e2ccb47a259b4747cc6 100644 (file)
@@ -1,3 +1,240 @@
+Version 1.02.77 - 15th October 2012
+===================================
+  Support unmount of thin volumes from pool above thin pool threshold.
+  Update man page to reflect that dm UUIDs are being mangled as well.
+  Apply 'dmsetup mangle' for dm UUIDs besides dm names.
+  Add 'mangled_uuid' and 'unmangled_uuid' fields to dmsetup info -c -o.
+  Mangle device UUID on dm_task_set_uuid/newuuid call if necessary.
+  Add dm_task_get_uuid_mangled/unmangled to libdevmapper.
+  Always reset delay_resume_if_new flag when stacking thin pool over anything.
+  Don't create value for dm_config_node and require dm_config_create_value call.
+  Check for existing new_name for dmsetup rename.
+  Fix memory leak in dmsetup _get_split_name() error path.
+
+Version 1.02.76 - 7th August 2012
+=================================
+  Add dm_vasprintf to libdevmapper.
+  Allow --noflush with dmsetup status and wait (for thin target).
+  Add dm_config_write_one_node to libdevmapper.
+  Support thin pool message release/reserve_metadata_snap in libdevmapper.
+  Support thin pool discards and external origin features in libdevmapper.
+  Add configure --enable-udev-rule-exec-detection to detect exec path in rules.
+  Use sbindir in udev rules by default and remove executable path detection.
+  Remove hard-coded paths for dmeventd fifos and use default-dm-run-dir.
+  Add configure --with-lvmetad-pidfile to remove hard-coded value.
+  Add configure --with-default-pid-dir for common directory with pid files.
+  Add configure --with-default-dm-run-dir to set run directory for dm tools.
+  Detect kernel_send() errors in cmirrord.
+  Add __attribute__ instrumentation to libdevmapper.h.
+  Print clean_bits instead of sync_bits in pull_state in cmirrord.
+  Add tests for errors from closedir(), close() in cmirrord.
+  Add documentation references in systemd units.
+  Remove veritysetup.  Now maintained with cryptsetup.
+
+Version 1.02.75 - 8th June 2012
+===============================
+  Upstream source repo now fedorahosted.org git not sources.redhat.com CVS.
+  Remove unsupported udev_get_dev_path libudev call used for checking udev dir.
+  Set delay_resume_if_new on deptree snapshot origin.
+  Log value chosen in _find_config_bool like other variable types do.
+  Wait for dmeventd to exit after sending it DM_EVENT_CMD_DIE when restarting.
+  Append 'Used' to {Blk}DevNames/DevNos dmsetup report headers for clarity.
+  Add configure --with-veritysetup for independent veritysetup tool.
+  Properly support supplied dmevent path in dm_event_register_handler().
+  Remove dmeventd fifos on exit if they are not managed by systemd.
+  Use SD_ACTIVATION environment variable in systemd units to detect systemd.
+  Only start a new dmeventd instance on restart if one was already running.
+  Extend the time waited for input from dmeventd fifo to 5 secs. (1.02.73)
+
+Version 1.02.74 - 6th March 2012
+================================
+  Check for multiply-mangled names in auto mangling mode.
+  Fix dm_task_get_name_unmangled to not unmangle already unmangled name.
+  Check whether device names are properly mangled on ioctl return.
+  Deactivation of failed thin check on thin pool returns success.
+
+Version 1.02.73 - 3rd March 2012
+================================
+  Test _thread_registry list with holding mutex in dmeventd.
+  Add dm_tree_node_set_callback() for preload and deactivation hooks.
+  Drop unsupported TRIM message for thin pool.
+  Improve logging for fifo startup in dmeventd.
+  Better detection of missing dmeventd fifo connection (1.02.71).
+  Add a few pointer validations in dmsetup.
+  Support dm_task_get_driver_version() query without version string.
+  Log failure of pthread_join when cleaning unused threads in dmeventd.
+  Fix empty string warning logic in _find_config_str. (1.02.68)
+  Fix dm_task_set_name to properly resolve path to dm name (1.02.71).
+  Add dm_strncpy() function as a faster strncpy() replacement.
+
+Version 1.02.72 - 23rd February 2012
+====================================
+  Avoid memory reallocation for dm_asprintf.
+
+Version 1.02.71 - 20th February 2012
+====================================
+  Switch to using built-in blkid in 13-dm-disk.rules.
+  Add "watch" rule to 13-dm-disk.rules.
+  Detect failing fifo and skip 20s retry communication period.
+  Add DM_DEFAULT_NAME_MANGLING_MODE environment variable as an override.
+  Add dm_lib_init to automatically initialise device-mapper library on load.
+  Replace any '\' char with '\\' in dm table specification on input.
+  Add mangle command to dmsetup to provide renaming to correct mangled form.
+  Add 'mangled_name' and 'unmangled_name' fields to dmsetup info -c -o.
+  Add --manglename option to dmsetup to select the name mangling mode.
+  Add dm_task_get_name_mangled/unmangled to libdevmapper.
+  Mangle device name on dm_task_set_name/newname call if necessary.
+  Add dm_set/get_name_mangling_mode to set/get name mangling in libdevmapper.
+  Add configure --with-default-name-mangling for udev-friendly dev name charset.
+  Test for parsed words in _umount() dmeventd snapshot plugin.
+  Fix memory leak in fail path of parse_loop_device_name() in dmsetup.
+  Check for missing reply_uuid in dm_event_get_registered_device().
+  Check for allocation failure in dmeventd restart().
+  Add few missing allocation failures tests in dmsetup.
+  Fix potential risk of writing in front of buffer in _sysfs_get_dm_name().
+
+Version 1.02.70 - 12th February 2012
+====================================
+  Fix dm_event_get_version() check.
+  Add pointer test for dependency check in _add_dev().
+  Validate name and uuid params of dm_tree_add_new_dev_with_udev_flags().
+  Do not crash for dm_report_init() sort_key == NULL and behave like "".
+  Return error for failing allocation in dm_asprintf().
+  Add missing test for failing allocation in dm_realloc() code.
+  Add test for memory allocation failures in regex matcher code.
+  Simplify dm_task_set_geometry() and use dm_asprintf().
+  Set all parameters to 0 for dm_get_next_target() for NULL return.
+  Fix fd resource leak in error path for _udev_notify_sem_create().
+  Leave space for '\0' for readline() call in _sysfs_get_kernel_name().
+
+Version 1.02.69 - 1st February 2012
+===================================
+  Clean up dmeventd systemd unit ordering and requirements.
+
+Version 1.02.68 - 26th January 2012
+===================================
+  Reset all members of info struct in dm_tree_add_new_dev_with_udev_flags.
+  Add dmsetup wipe_table to replace table with one that uses error target.
+  Add 'blkdevname' and 'blkdevs_used' fields to dmsetup info -c -o.
+  Add 'blkdevname' option to dmsetup ls --tree to see block device names.
+  Add -o devno/blkdevname/devname to dmsetup deps and ls.
+  Add dm_device_get_name to get map name or block device name for given devno.
+  Remove empty devices when clearing left-over inactive tables in deptree.
+  Add dm_uuid_prefix/dm_set_uuid_prefix to override hard-coded LVM- prefix.
+  Improve dmsetup man page description of readahead parameter.
+  Use sysfs to set/get readahead if possible.
+  Fix lvm2-monitor init script to use normalized output when using vgs.
+  Add test for max length (DM_MAX_TYPE_NAME) of target type name.
+  Include a copy of kernel DM documentation in doc/kernel.
+  Improve man page style for dmsetup and mention more targets.
+  Fix _get_proc_number to be tolerant of malformed /proc/misc entries.
+  Fix missing thread list manipulation protection in dmeventd.
+  Add ExecReload to dm-event.service for systemd to reload dmeventd properly.
+  Add dm_config_tree_find_str_allow_empty and dm_config_find_str_allow_empty.
+  Fix compile-time pool memory locking with DEBUG_MEM.
+  Fix valgrind error reports in free of pool chunks with DEBUG_MEM.
+  Align size of structure chunk for fast pool allocator to 8 bytes.
+  Simplify some pointer operations in dm_free_aux() debug code.
+  Remove unused dbg_malloc.h file from source tree.
+  Cleanup backtraces for _create_and_load_v4().
+  Fix alignment warning in bitcount calculation for raid segment.
+  Allocate dm_tree structure from dm_tree pool.
+  Update debug logging for _resume_node.
+  Add functions to support thin provisioning target.
+  Improve libdm-config error path reporting.
+  Update dmsetup resume man with --addnodeonresume/create options.
+  Add dependency for dm man pages to man subdirectory make all target.
+  Add dm_tree_retry_remove to use retry logic for device removal in a dm_tree.
+  Add dm_device_has_mounted_fs fn to check mounted filesystem on a device.
+  Add dm_device_has_holders fn to to check use of the device by another device.
+  Add dm_sysfs_dir to libdevmapper to retrieve sysfs location set.
+  Add dm_set_sysfs_dir to libdevmapper to set sysfs location.
+  Add --retry option for dmsetup remove to retry removal if not successful.
+  Add dm_task_retry_remove fn to use retry logic for device removal.
+  Remove unused passed parameters for _mirror_emit_segment_line().
+  Add dm_config and string character escaping functions to libdevmapper.
+  Mark unreleased memory pools as internal error.
+
+Version 1.02.67 - 19th August 2011
+==================================
+  Add dm_tree_node_add_null_area for temporarily-missing raid devs tracked.
+
+Version 1.02.66 - 12th August 2011
+==================================
+  Release geometry buffer in dm_task_destroy.
+  Update udev rules to skip DM flags decoding for removed devices.
+  Add compile-time pool memory locking options (to debug shared VG structs).
+  Remove device name prefix from dmsetup line output if -j & -m or -u supplied.
+  Remove support for the original version 1 dm ioctls.
+  Add missing check for allocation failure _create_dir_recursive().
+  Add support for systemd file descriptor handover in dmeventd.
+  Fix memory leak in dmsetup _message() memory allocation error path.
+  Use new oom killer adjustment interface (oom_score_adj) when available.
+  Add systemd unit files for dmeventd.
+  Fix read-only identical table reload supression.
+
+Version 1.02.65 - 8th July 2011
+===============================
+  Remove dev name prefix from dmsetup line output if exactly one dev requested.
+  Report internal error if suspending a device using an already-suspended dev.
+  Report error if a table load requiring target parameters has none supplied.
+  Add dmsetup --checks and dm_task_enable_checks framework to validate ioctls.
+  Add age_in_minutes parameter to dmsetup udevcomplete_all.
+  Return immediately from dm_lib_exit() if called more than once.
+  Disable udev fallback by default and add --verifyudev option to dmsetup.
+  Report internal error if any table is loaded while any dev is known suspended.
+  Add dm_get_suspended_counter() for number of devs in suspended state by lib.
+  Fix "all" report field prefix matching to include label fields with pv_all.
+  Delay resuming new preloaded mirror devices with core logs in deptree code.
+  Accept new kernel version 3 uname formats in initialisation.
+
+Version 1.02.64 - 29th April 2011
+==================================
+  Require libudev >= 143 when compiling with udev support.
+  Use word alignment for dm_pool_strdup() and dm_pool_strndup().
+  Use dm_snprintf() to fix signedness warning in dm_set_dev_dir().
+  Use unsigned loop counter to fix signedness warning in _other_node_ops().
+  Fix const cast in dmsetup calls of dm_report_field_string().
+  Streamline /dev/mapper/control node code for common cases.
+  Use hard-coded dm control node device number for 2.6.36 kernels and above.
+  Improve stack debug reporting in dm_task_create().
+  Fallback to control node creation only if node doesn't exist yet.
+  Change dm_hash binary functions to take void *key instead of char *.
+  Fix uninitialised memory use with empty params in _reload_with_suppression_v4.
+  Lower severity of selabel_lookup and matchpathcon failure to log_debug.
+  Add test for failed allocation from dm_task_set_uuid() in dmeventd.
+  Add dm_event_get_version to dmeventd for use with -R.
+  Avoid dmeventd core dumps when handling request with unknown command ID.
+  Have dmeventd -R start up even when no existing copy is running.
+  Accept multiple mapped device names on many dmsetup command lines.
+  Fix dm_udev_wait calls in dmsetup to occur before readahead display not after.
+  Include an implicit dm_task_update_nodes() within dm_udev_wait().
+  Fix _create_and_load_v4 not to lose the --addnodeoncreate setting (1.02.62).
+  Add inactive table query support for kernel driver >= 4.11.6 (RHEL 5.7).
+  Log debug open_count in _node_has_closed_parents().
+  Add a const to dm_report_field_string() data parameter.
+
+Version 1.02.63 - 9th February 2011
+===================================
+  Reinstate DEBUG_MEM as it's part of the API. (1.02.62)
+
+Version 1.02.62 - 4th February 2011
+===================================
+  Add configure --with-device-nodes-on=create for previous behaviour.
+  Move creation of device nodes from 'create' to 'resume'.
+  Add --addnodeonresume and --addnodeoncreate options to dmsetup.
+  Add dm_task_set_add_node to libdevmapper to control dev node creation time.
+  Add dm_task_secure_data to libdevmapper to wipe ioctl buffers in kernel.
+  Log debug message when expected uevent is not generated.
+  Only compile memory debugging code when DEBUG_MEM is set.
+  Set DM_UDEV_DISABLE_OTHER_RULES_FLAG for suspended DM devices in udev rules.
+  Begin a new pool object for each row in _output_as_rows() correctly.
+
+Version 1.02.61 - 10th January 2011
+===================================
+  Add DM_COOKIE_AUTO_CREATE to libdevmapper.h.
+  Export DM_CONTROL_NODE_UMASK and use it while creating /dev/mapper/control.
+
 Version 1.02.60 - 20th December 2010
 ====================================
   Check for unlink failure in remove_lockfile() in dmeventd.
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644 (file)
index 0000000..263b50e
--- /dev/null
@@ -0,0 +1,171 @@
+# generated automatically by aclocal 1.11.1 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2007, 2008, 2009  Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*-
+# serial 1 (pkg-config-0.24)
+# 
+# Copyright Â© 2004 Scott James Remnant <scott@netsplit.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (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.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
+# ----------------------------------
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
+AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
+AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+       AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+       _pkg_min_version=m4_default([$1], [0.9.0])
+       AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+       if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+               AC_MSG_RESULT([yes])
+       else
+               AC_MSG_RESULT([no])
+               PKG_CONFIG=""
+       fi
+fi[]dnl
+])# PKG_PROG_PKG_CONFIG
+
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# Check to see whether a particular set of modules exists.  Similar
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
+#
+# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+# only at the first occurence in configure.ac, so if the first place
+# it's called might be skipped (such as if it is within an "if", you
+# have to call PKG_CHECK_EXISTS manually
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+    AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+  m4_default([$2], [:])
+m4_ifvaln([$3], [else
+  $3])dnl
+fi])
+
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+# ---------------------------------------------
+m4_define([_PKG_CONFIG],
+[if test -n "$$1"; then
+    pkg_cv_[]$1="$$1"
+ elif test -n "$PKG_CONFIG"; then
+    PKG_CHECK_EXISTS([$3],
+                     [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
+                    [pkg_failed=yes])
+ else
+    pkg_failed=untried
+fi[]dnl
+])# _PKG_CONFIG
+
+# _PKG_SHORT_ERRORS_SUPPORTED
+# -----------------------------
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi[]dnl
+])# _PKG_SHORT_ERRORS_SUPPORTED
+
+
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+# [ACTION-IF-NOT-FOUND])
+#
+#
+# Note that if there is a possibility the first call to
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+#
+#
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+       AC_MSG_RESULT([no])
+        _PKG_SHORT_ERRORS_SUPPORTED
+        if test $_pkg_short_errors_supported = yes; then
+               $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "$2" 2>&1`
+        else 
+               $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors "$2" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+       m4_default([$4], [AC_MSG_ERROR(
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT])
+        ])
+elif test $pkg_failed = untried; then
+       AC_MSG_RESULT([no])
+       m4_default([$4], [AC_MSG_FAILURE(
+[The pkg-config script could not be found or is too old.  Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])
+        ])
+else
+       $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+       $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+        AC_MSG_RESULT([yes])
+       $3
+fi[]dnl
+])# PKG_CHECK_MODULES
+
index f32079abda668e5fc8f8de6f226e7b26384e8a03..dc84c68ef798c6a5000c78c6dd7380d34c9e0218 100755 (executable)
@@ -1,10 +1,10 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
 #   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
 #   Free Software Foundation, Inc.
 
-timestamp='2008-01-23'
+timestamp='2009-11-20'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -27,16 +27,16 @@ timestamp='2008-01-23'
 # the same distribution terms that you use for the rest of that program.
 
 
-# Originally written by Per Bothner <per@bothner.com>.
-# Please send patches to <config-patches@gnu.org>.  Submit a context
-# diff and a properly formatted ChangeLog entry.
+# Originally written by Per Bothner.  Please send patches (context
+# diff format) to <config-patches@gnu.org> and include a ChangeLog
+# entry.
 #
 # This script attempts to guess a canonical system name similar to
 # config.sub.  If it succeeds, it prints the system name on stdout, and
 # exits with 0.  Otherwise, it exits with 1.
 #
-# The plan is that this can be called by configure scripts if you
-# don't specify an explicit build system type.
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
 
 me=`echo "$0" | sed -e 's,.*/,,'`
 
@@ -170,7 +170,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
            arm*|i386|m68k|ns32k|sh3*|sparc|vax)
                eval $set_cc_for_build
                if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
-                       | grep __ELF__ >/dev/null
+                       | grep -q __ELF__
                then
                    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
                    # Return netbsd for either.  FIX?
@@ -324,14 +324,33 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
        case `/usr/bin/uname -p` in
            sparc) echo sparc-icl-nx7; exit ;;
        esac ;;
+    s390x:SunOS:*:*)
+       echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
     sun4H:SunOS:5.*:*)
        echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
        exit ;;
     sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
        echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
        exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+       echo i386-pc-auroraux${UNAME_RELEASE}
+       exit ;;
     i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
-       echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       eval $set_cc_for_build
+       SUN_ARCH="i386"
+       # If there is a compiler, see if it is configured for 64-bit objects.
+       # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+       # This test works for both compilers.
+       if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+           if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+               (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+               grep IS_64BIT_ARCH >/dev/null
+           then
+               SUN_ARCH="x86_64"
+           fi
+       fi
+       echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
        exit ;;
     sun4*:SunOS:6*:*)
        # According to config.sub, this is the proper way to canonicalize
@@ -640,7 +659,7 @@ EOF
            # => hppa64-hp-hpux11.23
 
            if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
-               grep __LP64__ >/dev/null
+               grep -q __LP64__
            then
                HP_ARCH="hppa2.0w"
            else
@@ -791,12 +810,12 @@ EOF
     i*:PW*:*)
        echo ${UNAME_MACHINE}-pc-pw32
        exit ;;
-    *:Interix*:[3456]*)
+    *:Interix*:*)
        case ${UNAME_MACHINE} in
            x86)
                echo i586-pc-interix${UNAME_RELEASE}
                exit ;;
-           EM64T | authenticamd)
+           authenticamd | genuineintel | EM64T)
                echo x86_64-unknown-interix${UNAME_RELEASE}
                exit ;;
            IA64)
@@ -806,6 +825,9 @@ EOF
     [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
        echo i${UNAME_MACHINE}-pc-mks
        exit ;;
+    8664:Windows_NT:*)
+       echo x86_64-pc-mks
+       exit ;;
     i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
        # How do we know it's Interix rather than the generic POSIX subsystem?
        # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
@@ -835,6 +857,20 @@ EOF
     i*86:Minix:*:*)
        echo ${UNAME_MACHINE}-pc-minix
        exit ;;
+    alpha:Linux:*:*)
+       case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+         EV5)   UNAME_MACHINE=alphaev5 ;;
+         EV56)  UNAME_MACHINE=alphaev56 ;;
+         PCA56) UNAME_MACHINE=alphapca56 ;;
+         PCA57) UNAME_MACHINE=alphapca56 ;;
+         EV6)   UNAME_MACHINE=alphaev6 ;;
+         EV67)  UNAME_MACHINE=alphaev67 ;;
+         EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+       objdump --private-headers /bin/sh | grep -q ld.so.1
+       if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+       echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+       exit ;;
     arm*:Linux:*:*)
        eval $set_cc_for_build
        if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
@@ -857,6 +893,17 @@ EOF
     frv:Linux:*:*)
        echo frv-unknown-linux-gnu
        exit ;;
+    i*86:Linux:*:*)
+       LIBC=gnu
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #ifdef __dietlibc__
+       LIBC=dietlibc
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+       echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+       exit ;;
     ia64:Linux:*:*)
        echo ${UNAME_MACHINE}-unknown-linux-gnu
        exit ;;
@@ -866,74 +913,33 @@ EOF
     m68*:Linux:*:*)
        echo ${UNAME_MACHINE}-unknown-linux-gnu
        exit ;;
-    mips:Linux:*:*)
-       eval $set_cc_for_build
-       sed 's/^        //' << EOF >$dummy.c
-       #undef CPU
-       #undef mips
-       #undef mipsel
-       #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
-       CPU=mipsel
-       #else
-       #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
-       CPU=mips
-       #else
-       CPU=
-       #endif
-       #endif
-EOF
-       eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
-           /^CPU/{
-               s: ::g
-               p
-           }'`"
-       test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
-       ;;
-    mips64:Linux:*:*)
+    mips:Linux:*:* | mips64:Linux:*:*)
        eval $set_cc_for_build
        sed 's/^        //' << EOF >$dummy.c
        #undef CPU
-       #undef mips64
-       #undef mips64el
+       #undef ${UNAME_MACHINE}
+       #undef ${UNAME_MACHINE}el
        #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
-       CPU=mips64el
+       CPU=${UNAME_MACHINE}el
        #else
        #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
-       CPU=mips64
+       CPU=${UNAME_MACHINE}
        #else
        CPU=
        #endif
        #endif
 EOF
-       eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
-           /^CPU/{
-               s: ::g
-               p
-           }'`"
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
        test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
        ;;
     or32:Linux:*:*)
        echo or32-unknown-linux-gnu
        exit ;;
-    ppc:Linux:*:*)
-       echo powerpc-unknown-linux-gnu
-       exit ;;
-    ppc64:Linux:*:*)
-       echo powerpc64-unknown-linux-gnu
+    padre:Linux:*:*)
+       echo sparc-unknown-linux-gnu
        exit ;;
-    alpha:Linux:*:*)
-       case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
-         EV5)   UNAME_MACHINE=alphaev5 ;;
-         EV56)  UNAME_MACHINE=alphaev56 ;;
-         PCA56) UNAME_MACHINE=alphapca56 ;;
-         PCA57) UNAME_MACHINE=alphapca56 ;;
-         EV6)   UNAME_MACHINE=alphaev6 ;;
-         EV67)  UNAME_MACHINE=alphaev67 ;;
-         EV68*) UNAME_MACHINE=alphaev68 ;;
-        esac
-       objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
-       if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
-       echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+       echo hppa64-unknown-linux-gnu
        exit ;;
     parisc:Linux:*:* | hppa:Linux:*:*)
        # Look for CPU level
@@ -943,8 +949,11 @@ EOF
          *)    echo hppa-unknown-linux-gnu ;;
        esac
        exit ;;
-    parisc64:Linux:*:* | hppa64:Linux:*:*)
-       echo hppa64-unknown-linux-gnu
+    ppc64:Linux:*:*)
+       echo powerpc64-unknown-linux-gnu
+       exit ;;
+    ppc:Linux:*:*)
+       echo powerpc-unknown-linux-gnu
        exit ;;
     s390:Linux:*:* | s390x:Linux:*:*)
        echo ${UNAME_MACHINE}-ibm-linux
@@ -967,69 +976,6 @@ EOF
     xtensa*:Linux:*:*)
        echo ${UNAME_MACHINE}-unknown-linux-gnu
        exit ;;
-    i*86:Linux:*:*)
-       # The BFD linker knows what the default object file format is, so
-       # first see if it will tell us. cd to the root directory to prevent
-       # problems with other programs or directories called `ld' in the path.
-       # Set LC_ALL=C to ensure ld outputs messages in English.
-       ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
-                        | sed -ne '/supported targets:/!d
-                                   s/[         ][      ]*/ /g
-                                   s/.*supported targets: *//
-                                   s/ .*//
-                                   p'`
-        case "$ld_supported_targets" in
-         elf32-i386)
-               TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
-               ;;
-         a.out-i386-linux)
-               echo "${UNAME_MACHINE}-pc-linux-gnuaout"
-               exit ;;
-         coff-i386)
-               echo "${UNAME_MACHINE}-pc-linux-gnucoff"
-               exit ;;
-         "")
-               # Either a pre-BFD a.out linker (linux-gnuoldld) or
-               # one that does not give us useful --help.
-               echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
-               exit ;;
-       esac
-       # Determine whether the default compiler is a.out or elf
-       eval $set_cc_for_build
-       sed 's/^        //' << EOF >$dummy.c
-       #include <features.h>
-       #ifdef __ELF__
-       # ifdef __GLIBC__
-       #  if __GLIBC__ >= 2
-       LIBC=gnu
-       #  else
-       LIBC=gnulibc1
-       #  endif
-       # else
-       LIBC=gnulibc1
-       # endif
-       #else
-       #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
-       LIBC=gnu
-       #else
-       LIBC=gnuaout
-       #endif
-       #endif
-       #ifdef __dietlibc__
-       LIBC=dietlibc
-       #endif
-EOF
-       eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
-           /^LIBC/{
-               s: ::g
-               p
-           }'`"
-       test x"${LIBC}" != x && {
-               echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
-               exit
-       }
-       test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
-       ;;
     i*86:DYNIX/ptx:4*:*)
        # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
        # earlier versions are messed up and put the nodename in both
@@ -1058,7 +1004,7 @@ EOF
     i*86:syllable:*:*)
        echo ${UNAME_MACHINE}-pc-syllable
        exit ;;
-    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
        echo i386-unknown-lynxos${UNAME_RELEASE}
        exit ;;
     i*86:*DOS:*:*)
@@ -1102,8 +1048,11 @@ EOF
     pc:*:*:*)
        # Left here for compatibility:
         # uname -m prints for DJGPP always 'pc', but it prints nothing about
-        # the processor, so we play safe by assuming i386.
-       echo i386-pc-msdosdjgpp
+        # the processor, so we play safe by assuming i586.
+       # Note: whatever this is, it MUST be the same as what config.sub
+       # prints for the "djgpp" host, or else GDB configury will decide that
+       # this is a cross-build.
+       echo i586-pc-msdosdjgpp
         exit ;;
     Intel:Mach:3*:*)
        echo i386-pc-mach3
@@ -1141,6 +1090,16 @@ EOF
     3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
         /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
           && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+       OS_REL='.3'
+       test -r /etc/.relid \
+           && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+           && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+           && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+       /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+           && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
     m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
        echo m68k-unknown-lynxos${UNAME_RELEASE}
        exit ;;
@@ -1153,7 +1112,7 @@ EOF
     rs6000:LynxOS:2.*:*)
        echo rs6000-unknown-lynxos${UNAME_RELEASE}
        exit ;;
-    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
        echo powerpc-unknown-lynxos${UNAME_RELEASE}
        exit ;;
     SM[BE]S:UNIX_SV:*:*)
@@ -1216,6 +1175,9 @@ EOF
     BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
        echo i586-pc-beos
        exit ;;
+    BePC:Haiku:*:*)    # Haiku running on Intel PC compatible.
+       echo i586-pc-haiku
+       exit ;;
     SX-4:SUPER-UX:*:*)
        echo sx4-nec-superux${UNAME_RELEASE}
        exit ;;
@@ -1243,6 +1205,16 @@ EOF
     *:Darwin:*:*)
        UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
        case $UNAME_PROCESSOR in
+           i386)
+               eval $set_cc_for_build
+               if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+                 if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+                     (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+                     grep IS_64BIT_ARCH >/dev/null
+                 then
+                     UNAME_PROCESSOR="x86_64"
+                 fi
+               fi ;;
            unknown) UNAME_PROCESSOR=powerpc ;;
        esac
        echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
@@ -1324,6 +1296,9 @@ EOF
     i*86:rdos:*:*)
        echo ${UNAME_MACHINE}-pc-rdos
        exit ;;
+    i*86:AROS:*:*)
+       echo ${UNAME_MACHINE}-pc-aros
+       exit ;;
 esac
 
 #echo '(No uname command or uname output not recognized.)' 1>&2
index 6759825a5b7fcf64476b4398dc0e30b3090b925c..2a55a50751c1aaf99de876b404ed613005dfcce1 100755 (executable)
@@ -1,10 +1,10 @@
 #! /bin/sh
 # Configuration validation subroutine script.
 #   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
 #   Free Software Foundation, Inc.
 
-timestamp='2008-01-16'
+timestamp='2009-11-20'
 
 # This file is (in principle) common to ALL GNU software.
 # The presence of a machine in this file suggests that SOME GNU software
@@ -32,13 +32,16 @@ timestamp='2008-01-16'
 
 
 # Please send patches to <config-patches@gnu.org>.  Submit a context
-# diff and a properly formatted ChangeLog entry.
+# diff and a properly formatted GNU ChangeLog entry.
 #
 # Configuration subroutine to validate and canonicalize a configuration type.
 # Supply the specified configuration type as an argument.
 # If it is invalid, we print an error message on stderr and exit with code 1.
 # Otherwise, we print the canonical config type on stdout and succeed.
 
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
 # This file is supposed to be the same for all GNU packages
 # and recognize all the CPU types, system types and aliases
 # that are meaningful with *any* GNU software.
@@ -122,6 +125,7 @@ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
 case $maybe_os in
   nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
   uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+  kopensolaris*-gnu* | \
   storm-chaos* | os2-emx* | rtmk-nova*)
     os=-$maybe_os
     basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
@@ -148,10 +152,13 @@ case $os in
        -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
        -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
        -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-       -apple | -axis | -knuth | -cray)
+       -apple | -axis | -knuth | -cray | -microblaze)
                os=
                basic_machine=$1
                ;;
+        -bluegene*)
+               os=-cnk
+               ;;
        -sim | -cisco | -oki | -wec | -winbond)
                os=
                basic_machine=$1
@@ -249,13 +256,16 @@ case $basic_machine in
        | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
        | i370 | i860 | i960 | ia64 \
        | ip2k | iq2000 \
+       | lm32 \
        | m32c | m32r | m32rle | m68000 | m68k | m88k \
-       | maxq | mb | microblaze | mcore | mep \
+       | maxq | mb | microblaze | mcore | mep | metag \
        | mips | mipsbe | mipseb | mipsel | mipsle \
        | mips16 \
        | mips64 | mips64el \
-       | mips64vr | mips64vrel \
+       | mips64octeon | mips64octeonel \
        | mips64orion | mips64orionel \
+       | mips64r5900 | mips64r5900el \
+       | mips64vr | mips64vrel \
        | mips64vr4100 | mips64vr4100el \
        | mips64vr4300 | mips64vr4300el \
        | mips64vr5000 | mips64vr5000el \
@@ -268,6 +278,7 @@ case $basic_machine in
        | mipsisa64sr71k | mipsisa64sr71kel \
        | mipstx39 | mipstx39el \
        | mn10200 | mn10300 \
+       | moxie \
        | mt \
        | msp430 \
        | nios | nios2 \
@@ -276,20 +287,22 @@ case $basic_machine in
        | pdp10 | pdp11 | pj | pjl \
        | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
        | pyramid \
+       | rx \
        | score \
-       | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+       | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
        | sh64 | sh64le \
        | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
        | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
        | spu | strongarm \
        | tahoe | thumb | tic4x | tic80 | tron \
+       | ubicom32 \
        | v850 | v850e \
        | we32k \
        | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
-       | z8k)
+       | z8k | z80)
                basic_machine=$basic_machine-unknown
                ;;
-       m6811 | m68hc11 | m6812 | m68hc12)
+       m6811 | m68hc11 | m6812 | m68hc12 | picochip)
                # Motorola 68HC11/12.
                basic_machine=$basic_machine-unknown
                os=-none
@@ -329,14 +342,17 @@ case $basic_machine in
        | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
        | i*86-* | i860-* | i960-* | ia64-* \
        | ip2k-* | iq2000-* \
+       | lm32-* \
        | m32c-* | m32r-* | m32rle-* \
        | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
-       | m88110-* | m88k-* | maxq-* | mcore-* \
+       | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
        | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
        | mips16-* \
        | mips64-* | mips64el-* \
-       | mips64vr-* | mips64vrel-* \
+       | mips64octeon-* | mips64octeonel-* \
        | mips64orion-* | mips64orionel-* \
+       | mips64r5900-* | mips64r5900el-* \
+       | mips64vr-* | mips64vrel-* \
        | mips64vr4100-* | mips64vr4100el-* \
        | mips64vr4300-* | mips64vr4300el-* \
        | mips64vr5000-* | mips64vr5000el-* \
@@ -357,21 +373,22 @@ case $basic_machine in
        | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
        | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
        | pyramid-* \
-       | romp-* | rs6000-* \
-       | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+       | romp-* | rs6000-* | rx-* \
+       | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
        | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
        | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
        | sparclite-* \
        | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
        | tahoe-* | thumb-* \
-       | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+       | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \
        | tron-* \
+       | ubicom32-* \
        | v850-* | v850e-* | vax-* \
        | we32k-* \
        | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
        | xstormy16-* | xtensa*-* \
        | ymp-* \
-       | z8k-*)
+       | z8k-* | z80-*)
                ;;
        # Recognize the basic CPU types without company name, with glob match.
        xtensa*)
@@ -439,6 +456,10 @@ case $basic_machine in
                basic_machine=m68k-apollo
                os=-bsd
                ;;
+       aros)
+               basic_machine=i386-pc
+               os=-aros
+               ;;
        aux)
                basic_machine=m68k-apple
                os=-aux
@@ -455,10 +476,18 @@ case $basic_machine in
                basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
                os=-linux
                ;;
+       bluegene*)
+               basic_machine=powerpc-ibm
+               os=-cnk
+               ;;
        c90)
                basic_machine=c90-cray
                os=-unicos
                ;;
+        cegcc)
+               basic_machine=arm-unknown
+               os=-cegcc
+               ;;
        convex-c1)
                basic_machine=c1-convex
                os=-bsd
@@ -526,6 +555,10 @@ case $basic_machine in
                basic_machine=m88k-motorola
                os=-sysv3
                ;;
+       dicos)
+               basic_machine=i686-pc
+               os=-dicos
+               ;;
        djgpp)
                basic_machine=i586-pc
                os=-msdosdjgpp
@@ -699,6 +732,9 @@ case $basic_machine in
                basic_machine=ns32k-utek
                os=-sysv
                ;;
+        microblaze)
+               basic_machine=microblaze-xilinx
+               ;;
        mingw32)
                basic_machine=i386-pc
                os=-mingw32
@@ -1128,6 +1164,10 @@ case $basic_machine in
                basic_machine=z8k-unknown
                os=-sim
                ;;
+       z80-*-coff)
+               basic_machine=z80-unknown
+               os=-sim
+               ;;
        none)
                basic_machine=none-none
                os=-none
@@ -1166,7 +1206,7 @@ case $basic_machine in
        we32k)
                basic_machine=we32k-att
                ;;
-       sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+       sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
                basic_machine=sh-unknown
                ;;
        sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
@@ -1216,6 +1256,9 @@ case $os in
         # First match some system type aliases
         # that might get confused with valid system types.
        # -solaris* is a basic system type, with this one exception.
+        -auroraux)
+               os=-auroraux
+               ;;
        -solaris1 | -solaris1.*)
                os=`echo $os | sed -e 's|solaris1|sunos4|'`
                ;;
@@ -1236,10 +1279,11 @@ case $os in
        # Each alternative MUST END IN A *, to match a version number.
        # -sysv* is not here because it comes later, after sysvr4.
        -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
-             | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
-             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+             | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+             | -sym* | -kopensolaris* \
              | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
-             | -aos* \
+             | -aos* | -aros* \
              | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
              | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
              | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
@@ -1248,7 +1292,7 @@ case $os in
              | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
              | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
              | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
-             | -chorusos* | -chorusrdb* \
+             | -chorusos* | -chorusrdb* | -cegcc* \
              | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
              | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
              | -uxpv* | -beos* | -mpeix* | -udk* \
@@ -1258,7 +1302,7 @@ case $os in
              | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
              | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
              | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
-             | -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
+             | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
        # Remember, each alternative MUST END IN *, to match a version number.
                ;;
        -qnx*)
@@ -1388,6 +1432,9 @@ case $os in
        -zvmoe)
                os=-zvmoe
                ;;
+       -dicos*)
+               os=-dicos
+               ;;
        -none)
                ;;
        *)
@@ -1585,7 +1632,7 @@ case $basic_machine in
                        -sunos*)
                                vendor=sun
                                ;;
-                       -aix*)
+                       -cnk*|-aix*)
                                vendor=ibm
                                ;;
                        -beos*)
index ef343f54ae9bb0b86e98edf11393d2e66ac8edf6..b58c52daa494cd1d37105028153b6c42a32e698c 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,18 +1,22 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.63.
+# Generated by GNU Autoconf 2.66.
+#
 #
 # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
-# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
+# Foundation, Inc.
+#
+#
 # This configure script is free software; the Free Software Foundation
 # gives unlimited permission to copy, distribute and modify it.
-## --------------------- ##
-## M4sh Initialization.  ##
-## --------------------- ##
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
 
 # Be more Bourne compatible
 DUALCASE=1; export DUALCASE # for MKS sh
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
   emulate sh
   NULLCMD=:
   # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
@@ -20,23 +24,15 @@ if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
   alias -g '${1+"$@"}'='"$@"'
   setopt NO_GLOB_SUBST
 else
-  case `(set -o) 2>/dev/null` in
-  *posix*) set -o posix ;;
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
 esac
-
 fi
 
 
-
-
-# PATH needs CR
-# Avoid depending upon Character Ranges.
-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
-as_cr_digits='0123456789'
-as_cr_alnum=$as_cr_Letters$as_cr_digits
-
 as_nl='
 '
 export as_nl
@@ -44,7 +40,13 @@ export as_nl
 as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
 as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
 as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
-if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
   as_echo='printf %s\n'
   as_echo_n='printf %s'
 else
@@ -55,7 +57,7 @@ else
     as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
     as_echo_n_body='eval
       arg=$1;
-      case $arg in
+      case $arg in #(
       *"$as_nl"*)
        expr "X$arg" : "X\\(.*\\)$as_nl";
        arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
@@ -78,13 +80,6 @@ if test "${PATH_SEPARATOR+set}" != set; then
   }
 fi
 
-# Support unset when possible.
-if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
-  as_unset=unset
-else
-  as_unset=false
-fi
-
 
 # IFS
 # We need space, tab and new line, in precisely that order.  Quoting is
@@ -94,15 +89,15 @@ fi
 IFS=" ""       $as_nl"
 
 # Find who we are.  Look in the path if we contain no directory separator.
-case $0 in
+case $0 in #((
   *[\\/]* ) as_myself=$0 ;;
   *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
-done
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
 IFS=$as_save_IFS
 
      ;;
@@ -114,12 +109,16 @@ if test "x$as_myself" = x; then
 fi
 if test ! -f "$as_myself"; then
   $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
-  { (exit 1); exit 1; }
+  exit 1
 fi
 
-# Work around bugs in pre-3.0 UWIN ksh.
-for as_var in ENV MAIL MAILPATH
-do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
 done
 PS1='$ '
 PS2='> '
@@ -131,7 +130,248 @@ export LC_ALL
 LANGUAGE=C
 export LANGUAGE
 
-# Required to use basename.
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+        /*)
+          for as_base in sh bash ksh sh5; do
+            # Try only shells that exist, to save several forks.
+            as_shell=$as_dir/$as_base
+            if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+                   { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+                  if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+          done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+             { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  # We cannot yet assume a decent shell, so we have to provide a
+       # neutralization value for shells without unset; and this also
+       # works around shells that cannot unset nonexistent variables.
+       BASH_ENV=/dev/null
+       ENV=/dev/null
+       (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+       export CONFIG_SHELL
+       exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
 if expr a : '\(a\)' >/dev/null 2>&1 &&
    test "X`expr 00001 : '.*\(...\)'`" = X001; then
   as_expr=expr
@@ -145,8 +385,12 @@ else
   as_basename=false
 fi
 
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
 
-# Name of the executable.
 as_me=`$as_basename -- "$0" ||
 $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
         X"$0" : 'X\(//\)$' \| \
@@ -166,415 +410,127 @@ $as_echo X/"$0" |
          }
          s/.*/./; q'`
 
-# CDPATH.
-$as_unset CDPATH
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
 
 
-if test "x$CONFIG_SHELL" = x; then
-  if (eval ":") 2>/dev/null; then
-  as_have_required=yes
-else
-  as_have_required=no
-fi
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
 
-  if test $as_have_required = yes &&    (eval ":
-(as_func_return () {
-  (exit \$1)
-}
-as_func_success () {
-  as_func_return 0
-}
-as_func_failure () {
-  as_func_return 1
-}
-as_func_ret_success () {
-  return 0
-}
-as_func_ret_failure () {
-  return 1
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
 }
 
-exitcode=0
-if as_func_success; then
-  :
-else
-  exitcode=1
-  echo as_func_success failed.
-fi
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='        ';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
 
-if as_func_failure; then
-  exitcode=1
-  echo as_func_failure succeeded.
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
 fi
-
-if as_func_ret_success; then
-  :
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
 else
-  exitcode=1
-  echo as_func_ret_success failed.
+  as_ln_s='cp -p'
 fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
 
-if as_func_ret_failure; then
-  exitcode=1
-  echo as_func_ret_failure succeeded.
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
 fi
 
-if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
-  :
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
 else
-  exitcode=1
-  echo positional parameters were not saved.
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+       test -d "$1/.";
+      else
+       case $1 in #(
+       -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
 fi
+as_executable_p=$as_test_x
 
-test \$exitcode = 0) || { (exit 1); exit 1; }
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
 
-(
-  as_lineno_1=\$LINENO
-  as_lineno_2=\$LINENO
-  test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" &&
-  test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; }
-") 2> /dev/null; then
-  :
-else
-  as_candidate_shells=
-    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  case $as_dir in
-        /*)
-          for as_base in sh bash ksh sh5; do
-            as_candidate_shells="$as_candidate_shells $as_dir/$as_base"
-          done;;
-       esac
-done
-IFS=$as_save_IFS
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
 
 
-      for as_shell in $as_candidate_shells $SHELL; do
-        # Try only shells that exist, to save several forks.
-        if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
-               { ("$as_shell") 2> /dev/null <<\_ASEOF
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
-  emulate sh
-  NULLCMD=:
-  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
-  # is contrary to our usage.  Disable this feature.
-  alias -g '${1+"$@"}'='"$@"'
-  setopt NO_GLOB_SUBST
-else
-  case `(set -o) 2>/dev/null` in
-  *posix*) set -o posix ;;
-esac
-
-fi
-
-
-:
-_ASEOF
-}; then
-  CONFIG_SHELL=$as_shell
-              as_have_required=yes
-              if { "$as_shell" 2> /dev/null <<\_ASEOF
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
-  emulate sh
-  NULLCMD=:
-  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
-  # is contrary to our usage.  Disable this feature.
-  alias -g '${1+"$@"}'='"$@"'
-  setopt NO_GLOB_SUBST
-else
-  case `(set -o) 2>/dev/null` in
-  *posix*) set -o posix ;;
-esac
-
-fi
-
-
-:
-(as_func_return () {
-  (exit $1)
-}
-as_func_success () {
-  as_func_return 0
-}
-as_func_failure () {
-  as_func_return 1
-}
-as_func_ret_success () {
-  return 0
-}
-as_func_ret_failure () {
-  return 1
-}
-
-exitcode=0
-if as_func_success; then
-  :
-else
-  exitcode=1
-  echo as_func_success failed.
-fi
-
-if as_func_failure; then
-  exitcode=1
-  echo as_func_failure succeeded.
-fi
-
-if as_func_ret_success; then
-  :
-else
-  exitcode=1
-  echo as_func_ret_success failed.
-fi
-
-if as_func_ret_failure; then
-  exitcode=1
-  echo as_func_ret_failure succeeded.
-fi
-
-if ( set x; as_func_ret_success y && test x = "$1" ); then
-  :
-else
-  exitcode=1
-  echo positional parameters were not saved.
-fi
-
-test $exitcode = 0) || { (exit 1); exit 1; }
-
-(
-  as_lineno_1=$LINENO
-  as_lineno_2=$LINENO
-  test "x$as_lineno_1" != "x$as_lineno_2" &&
-  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; }
-
-_ASEOF
-}; then
-  break
-fi
-
-fi
-
-      done
-
-      if test "x$CONFIG_SHELL" != x; then
-  for as_var in BASH_ENV ENV
-       do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
-       done
-       export CONFIG_SHELL
-       exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
-fi
-
-
-    if test $as_have_required = no; then
-  echo This script requires a shell more modern than all the
-      echo shells that I found on your system.  Please install a
-      echo modern shell, or manually run the script under such a
-      echo shell if you do have one.
-      { (exit 1); exit 1; }
-fi
-
-
-fi
-
-fi
-
-
-
-(eval "as_func_return () {
-  (exit \$1)
-}
-as_func_success () {
-  as_func_return 0
-}
-as_func_failure () {
-  as_func_return 1
-}
-as_func_ret_success () {
-  return 0
-}
-as_func_ret_failure () {
-  return 1
-}
-
-exitcode=0
-if as_func_success; then
-  :
-else
-  exitcode=1
-  echo as_func_success failed.
-fi
-
-if as_func_failure; then
-  exitcode=1
-  echo as_func_failure succeeded.
-fi
-
-if as_func_ret_success; then
-  :
-else
-  exitcode=1
-  echo as_func_ret_success failed.
-fi
-
-if as_func_ret_failure; then
-  exitcode=1
-  echo as_func_ret_failure succeeded.
-fi
-
-if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
-  :
-else
-  exitcode=1
-  echo positional parameters were not saved.
-fi
-
-test \$exitcode = 0") || {
-  echo No shell found that supports shell functions.
-  echo Please tell bug-autoconf@gnu.org about your system,
-  echo including any error possibly output before this message.
-  echo This can help us improve future autoconf versions.
-  echo Configuration will now proceed without shell functions.
-}
-
-
-
-  as_lineno_1=$LINENO
-  as_lineno_2=$LINENO
-  test "x$as_lineno_1" != "x$as_lineno_2" &&
-  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
-
-  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
-  # uniformly replaced by the line number.  The first 'sed' inserts a
-  # line-number line after each line using $LINENO; the second 'sed'
-  # does the real work.  The second script uses 'N' to pair each
-  # line-number line with the line containing $LINENO, and appends
-  # trailing '-' during substitution so that $LINENO is not a special
-  # case at line end.
-  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
-  # scripts with optimization help from Paolo Bonzini.  Blame Lee
-  # E. McMahon (1931-1989) for sed's syntax.  :-)
-  sed -n '
-    p
-    /[$]LINENO/=
-  ' <$as_myself |
-    sed '
-      s/[$]LINENO.*/&-/
-      t lineno
-      b
-      :lineno
-      N
-      :loop
-      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
-      t loop
-      s/-\n.*//
-    ' >$as_me.lineno &&
-  chmod +x "$as_me.lineno" ||
-    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
-   { (exit 1); exit 1; }; }
-
-  # Don't try to exec as it changes $[0], causing all sort of problems
-  # (the dirname of $[0] is not the place where we might find the
-  # original and so on.  Autoconf is especially sensitive to this).
-  . "./$as_me.lineno"
-  # Exit status is that of the last command.
-  exit
-}
-
-
-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
-  as_dirname=dirname
-else
-  as_dirname=false
-fi
-
-ECHO_C= ECHO_N= ECHO_T=
-case `echo -n x` in
--n*)
-  case `echo 'x\c'` in
-  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
-  *)   ECHO_C='\c';;
-  esac;;
-*)
-  ECHO_N='-n';;
-esac
-if expr a : '\(a\)' >/dev/null 2>&1 &&
-   test "X`expr 00001 : '.*\(...\)'`" = X001; then
-  as_expr=expr
-else
-  as_expr=false
-fi
-
-rm -f conf$$ conf$$.exe conf$$.file
-if test -d conf$$.dir; then
-  rm -f conf$$.dir/conf$$.file
-else
-  rm -f conf$$.dir
-  mkdir conf$$.dir 2>/dev/null
-fi
-if (echo >conf$$.file) 2>/dev/null; then
-  if ln -s conf$$.file conf$$ 2>/dev/null; then
-    as_ln_s='ln -s'
-    # ... but there are two gotchas:
-    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
-    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -p'.
-    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -p'
-  elif ln conf$$.file conf$$ 2>/dev/null; then
-    as_ln_s=ln
-  else
-    as_ln_s='cp -p'
-  fi
-else
-  as_ln_s='cp -p'
-fi
-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
-rmdir conf$$.dir 2>/dev/null
-
-if mkdir -p . 2>/dev/null; then
-  as_mkdir_p=:
-else
-  test -d ./-p && rmdir ./-p
-  as_mkdir_p=false
-fi
-
-if test -x / >/dev/null 2>&1; then
-  as_test_x='test -x'
-else
-  if ls -dL / >/dev/null 2>&1; then
-    as_ls_L_option=L
-  else
-    as_ls_L_option=
-  fi
-  as_test_x='
-    eval sh -c '\''
-      if test -d "$1"; then
-       test -d "$1/.";
-      else
-       case $1 in
-       -*)set "./$1";;
-       esac;
-       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
-       ???[sx]*):;;*)false;;esac;fi
-    '\'' sh
-  '
-fi
-as_executable_p=$as_test_x
-
-# Sed expression to map a string onto a valid CPP name.
-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
-
-# Sed expression to map a string onto a valid variable name.
-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
-
-
-
-exec 7<&0 </dev/null 6>&1
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
 
 # Name of the host.
-# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
 # so uname gets run too.
 ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
 
@@ -589,7 +545,6 @@ cross_compiling=no
 subdirs=
 MFLAGS=
 MAKEFLAGS=
-SHELL=${CONFIG_SHELL-/bin/sh}
 
 # Identity of this package.
 PACKAGE_NAME=
@@ -597,6 +552,7 @@ PACKAGE_TARNAME=
 PACKAGE_VERSION=
 PACKAGE_STRING=
 PACKAGE_BUGREPORT=
+PACKAGE_URL=
 
 ac_unique_file="lib/device/dev-cache.h"
 # Factoring default headers for most tests.
@@ -635,10 +591,14 @@ ac_includes_default="\
 # include <unistd.h>
 #endif"
 
+ac_header_list=
 ac_default_prefix=/usr
 ac_subst_vars='LTLIBOBJS
 usrsbindir
 usrlibdir
+tmpfilesdir
+systemdutildir
+systemdsystemunitdir
 udevdir
 udev_prefix
 tmpdir
@@ -646,26 +606,36 @@ kernelvsn
 missingkernel
 kerneldir
 interface
+LVMETAD_PIDFILE
+DMEVENTD_PIDFILE
 WRITE_INSTALL
+UDEV_HAS_BUILTIN_BLKID
+UDEV_RULE_EXEC_DETECTION
 UDEV_SYNC
 UDEV_RULES
 UDEV_PC
-UDEV_LIBS
+THIN
 TESTING
 STATIC_LINK
 STATICDIR
 SNAPSHOTS
 SELINUX_PC
 SELINUX_LIBS
+REPLICATORS
 READLINE_LIBS
+RAID
+PYTHON_LIBDIRS
+PYTHON_INCDIRS
+PYTHON_BINDINGS
 PTHREAD_LIBS
 POOL
 PKGCONFIG
-REPLICATORS
+OCFDIR
 OCF
 MIRRORS
 LVM_RELEASE_DATE
 LVM_RELEASE
+LVM_PATH
 LVM_PATCHLEVEL
 LVM_MINOR
 LVM_MAJOR
@@ -681,7 +651,9 @@ INTL_PACKAGE
 INTL
 HAVE_REALTIME
 HAVE_LIBDL
+BLKDEACTIVATE
 FSADM
+ELDFLAGS
 DM_LIB_PATCHLEVEL
 DM_LIB_VERSION
 DM_IOCTLS
@@ -694,6 +666,7 @@ DMEVENTD
 DL_LIBS
 DEVMAPPER
 DEFAULT_RUN_DIR
+DEFAULT_DM_RUN_DIR
 DEFAULT_LOCK_DIR
 DEFAULT_DATA_ALIGNMENT
 DEFAULT_CACHE_SUBDIR
@@ -704,21 +677,30 @@ DEBUG
 COPTIMISE_FLAG
 CONFDIR
 CMDLIB
+CLVMD_PATH
 CLVMD_CMANAGERS
 CLVMD
 CLUSTER
 CLDWHOLEARCHIVE
 CLDNOWHOLEARCHIVE
 CLDFLAGS
+BUILD_LVMETAD
 BUILD_DMEVENTD
 BUILD_CMIRRORD
 APPLIB
 MODPROBE_CMD
 MSGFMT
+PYTHON_CONFIG
+PYTHON
 LVM2CMD_LIB
 LVM2APP_LIB
-VALGRIND
-RUBY19
+UDEV_LIBS
+UDEV_CFLAGS
+VALGRIND_POOL
+VALGRIND_LIBS
+VALGRIND_CFLAGS
+CUNIT_LIBS
+CUNIT_CFLAGS
 GENPNG
 GENHTML
 LCOV
@@ -728,6 +710,8 @@ DLM_LIBS
 DLM_CFLAGS
 CPG_LIBS
 CPG_CFLAGS
+CMAP_LIBS
+CMAP_CFLAGS
 CONFDB_LIBS
 CONFDB_CFLAGS
 SALCK_LIBS
@@ -738,13 +722,12 @@ COROSYNC_LIBS
 COROSYNC_CFLAGS
 CMAN_LIBS
 CMAN_CFLAGS
-GULM_LIBS
-GULM_CFLAGS
-CCS_LIBS
-CCS_CFLAGS
 PKGCONFIGINIT_LIBS
 PKGCONFIGINIT_CFLAGS
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
 PKG_CONFIG
+THIN_CHECK_CMD
 POW_LIB
 LIBOBJS
 ALLOCA
@@ -811,6 +794,7 @@ bindir
 program_transform_name
 prefix
 exec_prefix
+PACKAGE_URL
 PACKAGE_BUGREPORT
 PACKAGE_STRING
 PACKAGE_VERSION
@@ -827,16 +811,25 @@ with_group
 with_device_uid
 with_device_gid
 with_device_mode
+with_device_nodes_on
+with_default_name_mangling
 enable_lvm1_fallback
 with_lvm1
 with_pool
 with_cluster
 with_snapshots
 with_mirrors
+with_raid
 with_replicators
+with_thin
+with_thin_check
 enable_readline
 enable_realtime
 enable_ocf
+with_ocfdir
+with_default_pid_dir
+with_default_dm_run_dir
+with_default_run_dir
 with_clvmd
 with_clvmd_pidfile
 enable_cmirrord
@@ -847,17 +840,22 @@ enable_profiling
 enable_testing
 enable_valgrind_pool
 enable_devmapper
+enable_lvmetad
+with_lvmetad_pidfile
 enable_udev_sync
 enable_udev_rules
+enable_udev_rule_exec_detection
 enable_compat
 enable_units_compat
 enable_ioctl
 enable_o_direct
 enable_applib
 enable_cmdlib
+enable_python_bindings
 enable_pkgconfig
 enable_write_install
 enable_fsadm
+enable_blkdeactivate
 enable_dmeventd
 enable_selinux
 enable_nls
@@ -868,9 +866,10 @@ with_usrlibdir
 with_usrsbindir
 with_udev_prefix
 with_udevdir
+with_systemdsystemunitdir
+with_tmpfilesdir
 with_dmeventd_pidfile
 with_dmeventd_path
-with_default_run_dir
 with_default_system_dir
 with_default_archive_subdir
 with_default_backup_subdir
@@ -889,12 +888,10 @@ LIBS
 CPPFLAGS
 CPP
 PKG_CONFIG
+PKG_CONFIG_PATH
+PKG_CONFIG_LIBDIR
 PKGCONFIGINIT_CFLAGS
 PKGCONFIGINIT_LIBS
-CCS_CFLAGS
-CCS_LIBS
-GULM_CFLAGS
-GULM_LIBS
 CMAN_CFLAGS
 CMAN_LIBS
 COROSYNC_CFLAGS
@@ -905,12 +902,20 @@ SALCK_CFLAGS
 SALCK_LIBS
 CONFDB_CFLAGS
 CONFDB_LIBS
+CMAP_CFLAGS
+CMAP_LIBS
 CPG_CFLAGS
 CPG_LIBS
 DLM_CFLAGS
 DLM_LIBS
 SACKPT_CFLAGS
-SACKPT_LIBS'
+SACKPT_LIBS
+CUNIT_CFLAGS
+CUNIT_LIBS
+VALGRIND_CFLAGS
+VALGRIND_LIBS
+UDEV_CFLAGS
+UDEV_LIBS'
 
 
 # Initialize some variables set by options.
@@ -1019,8 +1024,7 @@ do
     ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
     # Reject names that are not valid shell variable names.
     expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2
-   { (exit 1); exit 1; }; }
+      as_fn_error $? "invalid feature name: $ac_useropt"
     ac_useropt_orig=$ac_useropt
     ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
     case $ac_user_opts in
@@ -1046,8 +1050,7 @@ do
     ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
     # Reject names that are not valid shell variable names.
     expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2
-   { (exit 1); exit 1; }; }
+      as_fn_error $? "invalid feature name: $ac_useropt"
     ac_useropt_orig=$ac_useropt
     ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
     case $ac_user_opts in
@@ -1251,8 +1254,7 @@ do
     ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
     # Reject names that are not valid shell variable names.
     expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2
-   { (exit 1); exit 1; }; }
+      as_fn_error $? "invalid package name: $ac_useropt"
     ac_useropt_orig=$ac_useropt
     ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
     case $ac_user_opts in
@@ -1268,8 +1270,7 @@ do
     ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
     # Reject names that are not valid shell variable names.
     expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2
-   { (exit 1); exit 1; }; }
+      as_fn_error $? "invalid package name: $ac_useropt"
     ac_useropt_orig=$ac_useropt
     ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
     case $ac_user_opts in
@@ -1299,17 +1300,17 @@ do
   | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
     x_libraries=$ac_optarg ;;
 
-  -*) { $as_echo "$as_me: error: unrecognized option: $ac_option
-Try \`$0 --help' for more information." >&2
-   { (exit 1); exit 1; }; }
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
     ;;
 
   *=*)
     ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
     # Reject names that are not valid shell variable names.
-    expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
-      { $as_echo "$as_me: error: invalid variable name: $ac_envvar" >&2
-   { (exit 1); exit 1; }; }
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
     eval $ac_envvar=\$ac_optarg
     export $ac_envvar ;;
 
@@ -1326,15 +1327,13 @@ done
 
 if test -n "$ac_prev"; then
   ac_option=--`echo $ac_prev | sed 's/_/-/g'`
-  { $as_echo "$as_me: error: missing argument to $ac_option" >&2
-   { (exit 1); exit 1; }; }
+  as_fn_error $? "missing argument to $ac_option"
 fi
 
 if test -n "$ac_unrecognized_opts"; then
   case $enable_option_checking in
     no) ;;
-    fatal) { $as_echo "$as_me: error: unrecognized options: $ac_unrecognized_opts" >&2
-   { (exit 1); exit 1; }; } ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
     *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
   esac
 fi
@@ -1357,8 +1356,7 @@ do
     [\\/$]* | ?:[\\/]* )  continue;;
     NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
   esac
-  { $as_echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
-   { (exit 1); exit 1; }; }
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
 done
 
 # There might be people who depend on the old broken behavior: `$host'
@@ -1372,8 +1370,8 @@ target=$target_alias
 if test "x$host_alias" != x; then
   if test "x$build_alias" = x; then
     cross_compiling=maybe
-    $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
-    If a cross compiler is detected then cross compile mode will be used." >&2
+    $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used" >&2
   elif test "x$build_alias" != "x$host_alias"; then
     cross_compiling=yes
   fi
@@ -1388,11 +1386,9 @@ test "$silent" = yes && exec 6>/dev/null
 ac_pwd=`pwd` && test -n "$ac_pwd" &&
 ac_ls_di=`ls -di .` &&
 ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
-  { $as_echo "$as_me: error: working directory cannot be determined" >&2
-   { (exit 1); exit 1; }; }
+  as_fn_error $? "working directory cannot be determined"
 test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
-  { $as_echo "$as_me: error: pwd does not report name of working directory" >&2
-   { (exit 1); exit 1; }; }
+  as_fn_error $? "pwd does not report name of working directory"
 
 
 # Find the source files, if location was not specified.
@@ -1431,13 +1427,11 @@ else
 fi
 if test ! -r "$srcdir/$ac_unique_file"; then
   test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
-  { $as_echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
-   { (exit 1); exit 1; }; }
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
 fi
 ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
 ac_abs_confdir=`(
-       cd "$srcdir" && test -r "./$ac_unique_file" || { $as_echo "$as_me: error: $ac_msg" >&2
-   { (exit 1); exit 1; }; }
+       cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
        pwd)`
 # When building in place, set srcdir=.
 if test "$ac_abs_confdir" = "$ac_pwd"; then
@@ -1477,7 +1471,7 @@ Configuration:
       --help=short        display options specific to this package
       --help=recursive    display the short help of all the included packages
   -V, --version           display version information and exit
-  -q, --quiet, --silent   do not print \`checking...' messages
+  -q, --quiet, --silent   do not print \`checking ...' messages
       --cache-file=FILE   cache test results in FILE [disabled]
   -C, --config-cache      alias for \`--cache-file=config.cache'
   -n, --no-create         do not create output files
@@ -1549,8 +1543,11 @@ Optional Features:
   --enable-testing        enable testing targets in the makefile
   --enable-valgrind-pool  enable valgrind awareness of pools
   --disable-devmapper     disable LVM2 device-mapper interaction
+  --enable-lvmetad        enable the LVM Metadata Daemon
   --enable-udev_sync      enable synchronisation with udev processing
   --enable-udev_rules     install rule files needed for udev synchronisation
+  --enable-udev-rule-exec-detection
+                          enable executable path detection in udev rules
   --enable-compat         enable support for old device-mapper versions
   --enable-units-compat   enable output compatibility with old versions that
                           that do not use KiB-style unit suffixes
@@ -1558,9 +1555,12 @@ Optional Features:
   --disable-o_direct      disable O_DIRECT
   --enable-applib         build application library
   --enable-cmdlib         build shared command library
+  --enable-python_bindings
+                          build Python applib bindings
   --enable-pkgconfig      install pkgconfig support
   --enable-write_install  install user writable files
   --disable-fsadm         disable fsadm
+  --disable-blkdeactivate disable blkdeactivate
   --enable-dmeventd       enable the device-mapper event daemon
   --disable-selinux       disable selinux support
   --enable-nls            enable Native Language Support
@@ -1568,26 +1568,43 @@ Optional Features:
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
-  --with-user=USER        set the owner of installed files [USER=]
-  --with-group=GROUP      set the group owner of installed files [GROUP=]
-  --with-device-uid=UID   set the owner used for new device nodes [UID=0]
-  --with-device-gid=GID   set the group used for new device nodes [GID=0]
-  --with-device-mode=MODE set the mode used for new device nodes [MODE=0600]
+  --with-user=USER        set the owner of installed files [[USER=]]
+  --with-group=GROUP      set the group owner of installed files [[GROUP=]]
+  --with-device-uid=UID   set the owner used for new device nodes [[UID=0]]
+  --with-device-gid=GID   set the group used for new device nodes [[GID=0]]
+  --with-device-mode=MODE set the mode used for new device nodes [[MODE=0600]]
+  --with-device-nodes-on=ON
+                          create nodes on resume or create [[ON=resume]]
+  --with-default-name-mangling=MANGLING
+                          default name mangling: auto/none/hex
+                          [[MANGLING=auto]]
   --with-lvm1=TYPE        LVM1 metadata support: internal/shared/none
-                          [TYPE=internal]
+                          [[TYPE=internal]]
   --with-pool=TYPE        GFS pool read-only support: internal/shared/none
-                          [TYPE=internal]
+                          [[TYPE=internal]]
   --with-cluster=TYPE     cluster LVM locking support: internal/shared/none
-                          [TYPE=internal]
+                          [[TYPE=internal]]
   --with-snapshots=TYPE   snapshot support: internal/shared/none
-                          [TYPE=internal]
+                          [[TYPE=internal]]
   --with-mirrors=TYPE     mirror support: internal/shared/none
-                          [TYPE=internal]
+                          [[TYPE=internal]]
+  --with-raid=TYPE        mirror support: internal/shared/none
+                          [[TYPE=internal]]
   --with-replicators=TYPE replicator support: internal/shared/none
-                          [TYPE=none]
+                          [[TYPE=none]]
+  --with-thin=TYPE        thin provisioning support: internal/shared/none
+                          [[TYPE=none]]
+  --with-thin-check=PATH  thin_check tool: [[autodetect]]
+  --with-ocfdir=DIR       install OCF files in DIR
+                          [[PREFIX/lib/ocf/resource.d/lvm2]]
+  --with-default-pid-dir=PID_DIR
+                          Default directory to keep PID files in. [[/var/run]]
+  --with-default-dm-run-dir=DM_RUN_DIR
+                          Default DM run directory. [[/var/run]]
+  --with-default-run-dir=RUN_DIR
+                          Default LVM run directory. [[/var/run/lvm]]
   --with-clvmd=TYPE       build cluster LVM Daemon
                           The following cluster manager combinations are valid:
-                           * cman,gulm             (RHEL4 or equivalent)
                            * cman                  (RHEL5 or equivalent)
                            * cman,corosync,openais (or selection of them)
                            * singlenode            (localhost only)
@@ -1595,36 +1612,42 @@ Optional Packages:
                            * none                  (disable build)
                           [TYPE=none]
   --with-clvmd-pidfile=PATH
-                          clvmd pidfile [/var/run/clvmd.pid]
+                          clvmd pidfile [[PID_DIR/clvmd.pid]]
   --with-cmirrord-pidfile=PATH
-                          cmirrord pidfile [/var/run/cmirrord.pid]
-  --with-optimisation=OPT C optimisation flag [OPT=-O2]
-  --with-localedir=DIR    translation files in DIR [PREFIX/share/locale]
-  --with-confdir=DIR      configuration files in DIR [/etc]
-  --with-staticdir=DIR    static binaries in DIR [EPREFIX/sbin]
-  --with-usrlibdir=DIR    usrlib in DIR [PREFIX/lib]
-  --with-usrsbindir=DIR   usrsbin executables in DIR [PREFIX/sbin]
+                          cmirrord pidfile [[PID_DIR/cmirrord.pid]]
+  --with-optimisation=OPT C optimisation flag [[OPT=-O2]]
+  --with-lvmetad-pidfile=PATH
+                          lvmetad pidfile [[PID_DIR/lvmetad.pid]]
+  --with-localedir=DIR    translation files in DIR [[PREFIX/share/locale]]
+  --with-confdir=DIR      configuration files in DIR [[/etc]]
+  --with-staticdir=DIR    static binaries in DIR [[EPREFIX/sbin]]
+  --with-usrlibdir=DIR    usrlib in DIR [[PREFIX/lib]]
+  --with-usrsbindir=DIR   usrsbin executables in DIR [[PREFIX/sbin]]
   --with-udev-prefix=UPREFIX
-                          install udev rule files in UPREFIX [EPREFIX]
-  --with-udevdir=DIR      udev rules in DIR [UPREFIX/lib/udev/rules.d]
+                          install udev rule files in UPREFIX [[EPREFIX]]
+  --with-udevdir=DIR      udev rules in DIR [[UPREFIX/lib/udev/rules.d]]
+  --with-systemdsystemunitdir=DIR
+                          systemd service files in DIR
+  --with-tmpfilesdir=DIR  install configuration files for management of
+                          volatile files and directories in DIR
+                          [[PREFIX/lib/tmpfiles.d]]
   --with-dmeventd-pidfile=PATH
-                          dmeventd pidfile [/var/run/dmeventd.pid]
+                          dmeventd pidfile [[PID_DIR/dmeventd.pid]]
   --with-dmeventd-path=PATH
-                          dmeventd path [EPREFIX/sbin/dmeventd]
-  --with-default-run-dir=DIR       Default run directory [/var/run/lvm]
+                          dmeventd path [[EPREFIX/sbin/dmeventd]]
   --with-default-system-dir=DIR
-                          default LVM system directory [/etc/lvm]
+                          default LVM system directory [[/etc/lvm]]
   --with-default-archive-subdir=SUBDIR
-                          default metadata archive subdir [archive]
+                          default metadata archive subdir [[archive]]
   --with-default-backup-subdir=SUBDIR
-                          default metadata backup subdir [backup]
+                          default metadata backup subdir [[backup]]
   --with-default-cache-subdir=SUBDIR
-                          default metadata cache subdir [cache]
+                          default metadata cache subdir [[cache]]
   --with-default-locking-dir=DIR
-                          default locking directory [/var/lock/lvm]
+                          default locking directory [[/var/lock/lvm]]
   --with-default-data-alignment=NUM
-                          set the default data alignment in MiB [1]
-  --with-interface=IFACE  choose kernel interface (ioctl) [ioctl]
+                          set the default data alignment in MiB [[1]]
+  --with-interface=IFACE  choose kernel interface (ioctl) [[ioctl]]
 
 Some influential environment variables:
   CC          C compiler command
@@ -1632,18 +1655,18 @@ Some influential environment variables:
   LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
               nonstandard directory <lib dir>
   LIBS        libraries to pass to the linker, e.g. -l<library>
-  CPPFLAGS    C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
               you have headers in a nonstandard directory <include dir>
   CPP         C preprocessor
   PKG_CONFIG  path to pkg-config utility
+  PKG_CONFIG_PATH
+              directories to add to pkg-config's search path
+  PKG_CONFIG_LIBDIR
+              path overriding pkg-config's built-in search path
   PKGCONFIGINIT_CFLAGS
               C compiler flags for PKGCONFIGINIT, overriding pkg-config
   PKGCONFIGINIT_LIBS
               linker flags for PKGCONFIGINIT, overriding pkg-config
-  CCS_CFLAGS  C compiler flags for CCS, overriding pkg-config
-  CCS_LIBS    linker flags for CCS, overriding pkg-config
-  GULM_CFLAGS C compiler flags for GULM, overriding pkg-config
-  GULM_LIBS   linker flags for GULM, overriding pkg-config
   CMAN_CFLAGS C compiler flags for CMAN, overriding pkg-config
   CMAN_LIBS   linker flags for CMAN, overriding pkg-config
   COROSYNC_CFLAGS
@@ -1659,6 +1682,8 @@ Some influential environment variables:
   CONFDB_CFLAGS
               C compiler flags for CONFDB, overriding pkg-config
   CONFDB_LIBS linker flags for CONFDB, overriding pkg-config
+  CMAP_CFLAGS C compiler flags for CMAP, overriding pkg-config
+  CMAP_LIBS   linker flags for CMAP, overriding pkg-config
   CPG_CFLAGS  C compiler flags for CPG, overriding pkg-config
   CPG_LIBS    linker flags for CPG, overriding pkg-config
   DLM_CFLAGS  C compiler flags for DLM, overriding pkg-config
@@ -1666,10 +1691,20 @@ Some influential environment variables:
   SACKPT_CFLAGS
               C compiler flags for SACKPT, overriding pkg-config
   SACKPT_LIBS linker flags for SACKPT, overriding pkg-config
+  CUNIT_CFLAGS
+              C compiler flags for CUNIT, overriding pkg-config
+  CUNIT_LIBS  linker flags for CUNIT, overriding pkg-config
+  VALGRIND_CFLAGS
+              C compiler flags for VALGRIND, overriding pkg-config
+  VALGRIND_LIBS
+              linker flags for VALGRIND, overriding pkg-config
+  UDEV_CFLAGS C compiler flags for UDEV, overriding pkg-config
+  UDEV_LIBS   linker flags for UDEV, overriding pkg-config
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
 
+Report bugs to the package provider.
 _ACEOF
 ac_status=$?
 fi
@@ -1733,12264 +1768,5792 @@ test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
 configure
-generated by GNU Autoconf 2.63
+generated by GNU Autoconf 2.66
 
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
-2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+Copyright (C) 2010 Free Software Foundation, Inc.
 This configure script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it.
 _ACEOF
   exit
 fi
-cat >config.log <<_ACEOF
-This file contains any messages produced by compilers while
-running configure, to aid debugging if configure makes a mistake.
 
-It was created by $as_me, which was
-generated by GNU Autoconf 2.63.  Invocation command line was
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
 
-  $ $0 $@
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
 
-_ACEOF
-exec 5>>config.log
+       ac_retval=1
+fi
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
 {
-cat <<_ASUNAME
-## --------- ##
-## Platform. ##
-## --------- ##
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
 
-hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
-uname -m = `(uname -m) 2>/dev/null || echo unknown`
-uname -r = `(uname -r) 2>/dev/null || echo unknown`
-uname -s = `(uname -s) 2>/dev/null || echo unknown`
-uname -v = `(uname -v) 2>/dev/null || echo unknown`
+    ac_retval=1
+fi
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
 
-/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
-/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+} # ac_fn_c_try_cpp
 
-/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
-/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
-/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
-/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
-/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
-/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
-
-_ASUNAME
-
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  $as_echo "PATH: $as_dir"
-done
-IFS=$as_save_IFS
-
-} >&5
-
-cat >&5 <<_ACEOF
-
-
-## ----------- ##
-## Core tests. ##
-## ----------- ##
-
-_ACEOF
-
-
-# Keep a trace of the command line.
-# Strip out --no-create and --no-recursion so they do not pile up.
-# Strip out --silent because we don't want to record it for future runs.
-# Also quote any args containing shell meta-characters.
-# Make two passes to allow for proper duplicate-argument suppression.
-ac_configure_args=
-ac_configure_args0=
-ac_configure_args1=
-ac_must_keep_next=false
-for ac_pass in 1 2
-do
-  for ac_arg
-  do
-    case $ac_arg in
-    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
-    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
-    | -silent | --silent | --silen | --sile | --sil)
-      continue ;;
-    *\'*)
-      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
-    esac
-    case $ac_pass in
-    1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
-    2)
-      ac_configure_args1="$ac_configure_args1 '$ac_arg'"
-      if test $ac_must_keep_next = true; then
-       ac_must_keep_next=false # Got value, back to normal.
-      else
-       case $ac_arg in
-         *=* | --config-cache | -C | -disable-* | --disable-* \
-         | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
-         | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
-         | -with-* | --with-* | -without-* | --without-* | --x)
-           case "$ac_configure_args0 " in
-             "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
-           esac
-           ;;
-         -* ) ac_must_keep_next=true ;;
-       esac
-      fi
-      ac_configure_args="$ac_configure_args '$ac_arg'"
-      ;;
-    esac
-  done
-done
-$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
-$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
-
-# When interrupted or exit'd, cleanup temporary files, and complete
-# config.log.  We remove comments because anyway the quotes in there
-# would cause problems or look ugly.
-# WARNING: Use '\'' to represent an apostrophe within the trap.
-# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
-trap 'exit_status=$?
-  # Save into config.log some information that might help in debugging.
-  {
-    echo
-
-    cat <<\_ASBOX
-## ---------------- ##
-## Cache variables. ##
-## ---------------- ##
-_ASBOX
-    echo
-    # The following way of writing the cache mishandles newlines in values,
-(
-  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
-    eval ac_val=\$$ac_var
-    case $ac_val in #(
-    *${as_nl}*)
-      case $ac_var in #(
-      *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5
-$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
-      esac
-      case $ac_var in #(
-      _ | IFS | as_nl) ;; #(
-      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
-      *) $as_unset $ac_var ;;
-      esac ;;
-    esac
-  done
-  (set) 2>&1 |
-    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
-    *${as_nl}ac_space=\ *)
-      sed -n \
-       "s/'\''/'\''\\\\'\'''\''/g;
-         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
-      ;; #(
-    *)
-      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
-      ;;
-    esac |
-    sort
-)
-    echo
-
-    cat <<\_ASBOX
-## ----------------- ##
-## Output variables. ##
-## ----------------- ##
-_ASBOX
-    echo
-    for ac_var in $ac_subst_vars
-    do
-      eval ac_val=\$$ac_var
-      case $ac_val in
-      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
-      esac
-      $as_echo "$ac_var='\''$ac_val'\''"
-    done | sort
-    echo
-
-    if test -n "$ac_subst_files"; then
-      cat <<\_ASBOX
-## ------------------- ##
-## File substitutions. ##
-## ------------------- ##
-_ASBOX
-      echo
-      for ac_var in $ac_subst_files
-      do
-       eval ac_val=\$$ac_var
-       case $ac_val in
-       *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
-       esac
-       $as_echo "$ac_var='\''$ac_val'\''"
-      done | sort
-      echo
-    fi
-
-    if test -s confdefs.h; then
-      cat <<\_ASBOX
-## ----------- ##
-## confdefs.h. ##
-## ----------- ##
-_ASBOX
-      echo
-      cat confdefs.h
-      echo
-    fi
-    test "$ac_signal" != 0 &&
-      $as_echo "$as_me: caught signal $ac_signal"
-    $as_echo "$as_me: exit $exit_status"
-  } >&5
-  rm -f core *.core core.conftest.* &&
-    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
-    exit $exit_status
-' 0
-for ac_signal in 1 2 13 15; do
-  trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
-done
-ac_signal=0
-
-# confdefs.h avoids OS command line length limits that DEFS can exceed.
-rm -f -r conftest* confdefs.h
-
-# Predefined preprocessor variables.
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_NAME "$PACKAGE_NAME"
-_ACEOF
-
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
-_ACEOF
-
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_VERSION "$PACKAGE_VERSION"
-_ACEOF
-
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_STRING "$PACKAGE_STRING"
-_ACEOF
-
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
-_ACEOF
-
-
-# Let the site file select an alternate cache file if it wants to.
-# Prefer an explicitly selected file to automatically selected ones.
-ac_site_file1=NONE
-ac_site_file2=NONE
-if test -n "$CONFIG_SITE"; then
-  ac_site_file1=$CONFIG_SITE
-elif test "x$prefix" != xNONE; then
-  ac_site_file1=$prefix/share/config.site
-  ac_site_file2=$prefix/etc/config.site
-else
-  ac_site_file1=$ac_default_prefix/share/config.site
-  ac_site_file2=$ac_default_prefix/etc/config.site
-fi
-for ac_site_file in "$ac_site_file1" "$ac_site_file2"
-do
-  test "x$ac_site_file" = xNONE && continue
-  if test -r "$ac_site_file"; then
-    { $as_echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
-$as_echo "$as_me: loading site script $ac_site_file" >&6;}
-    sed 's/^/| /' "$ac_site_file" >&5
-    . "$ac_site_file"
-  fi
-done
-
-if test -r "$cache_file"; then
-  # Some versions of bash will fail to source /dev/null (special
-  # files actually), so we avoid doing that.
-  if test -f "$cache_file"; then
-    { $as_echo "$as_me:$LINENO: loading cache $cache_file" >&5
-$as_echo "$as_me: loading cache $cache_file" >&6;}
-    case $cache_file in
-      [\\/]* | ?:[\\/]* ) . "$cache_file";;
-      *)                      . "./$cache_file";;
-    esac
-  fi
-else
-  { $as_echo "$as_me:$LINENO: creating cache $cache_file" >&5
-$as_echo "$as_me: creating cache $cache_file" >&6;}
-  >$cache_file
-fi
-
-# Check that the precious variables saved in the cache have kept the same
-# value.
-ac_cache_corrupted=false
-for ac_var in $ac_precious_vars; do
-  eval ac_old_set=\$ac_cv_env_${ac_var}_set
-  eval ac_new_set=\$ac_env_${ac_var}_set
-  eval ac_old_val=\$ac_cv_env_${ac_var}_value
-  eval ac_new_val=\$ac_env_${ac_var}_value
-  case $ac_old_set,$ac_new_set in
-    set,)
-      { $as_echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
-$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
-      ac_cache_corrupted=: ;;
-    ,set)
-      { $as_echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
-$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
-      ac_cache_corrupted=: ;;
-    ,);;
-    *)
-      if test "x$ac_old_val" != "x$ac_new_val"; then
-       # differences in whitespace do not lead to failure.
-       ac_old_val_w=`echo x $ac_old_val`
-       ac_new_val_w=`echo x $ac_new_val`
-       if test "$ac_old_val_w" != "$ac_new_val_w"; then
-         { $as_echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
-$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
-         ac_cache_corrupted=:
-       else
-         { $as_echo "$as_me:$LINENO: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
-$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
-         eval $ac_var=\$ac_old_val
-       fi
-       { $as_echo "$as_me:$LINENO:   former value:  \`$ac_old_val'" >&5
-$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
-       { $as_echo "$as_me:$LINENO:   current value: \`$ac_new_val'" >&5
-$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
-      fi;;
-  esac
-  # Pass precious variables to config.status.
-  if test "$ac_new_set" = set; then
-    case $ac_new_val in
-    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
-    *) ac_arg=$ac_var=$ac_new_val ;;
-    esac
-    case " $ac_configure_args " in
-      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
-      *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
-    esac
-  fi
-done
-if $ac_cache_corrupted; then
-  { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-  { $as_echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
-$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
-  { { $as_echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
-$as_echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
-   { (exit 1); exit 1; }; }
-fi
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
-
-ac_config_headers="$ac_config_headers lib/misc/configure.h"
-
-
-################################################################################
-ac_aux_dir=
-for ac_dir in autoconf "$srcdir"/autoconf; do
-  if test -f "$ac_dir/install-sh"; then
-    ac_aux_dir=$ac_dir
-    ac_install_sh="$ac_aux_dir/install-sh -c"
-    break
-  elif test -f "$ac_dir/install.sh"; then
-    ac_aux_dir=$ac_dir
-    ac_install_sh="$ac_aux_dir/install.sh -c"
-    break
-  elif test -f "$ac_dir/shtool"; then
-    ac_aux_dir=$ac_dir
-    ac_install_sh="$ac_aux_dir/shtool install -c"
-    break
-  fi
-done
-if test -z "$ac_aux_dir"; then
-  { { $as_echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in autoconf \"$srcdir\"/autoconf" >&5
-$as_echo "$as_me: error: cannot find install-sh or install.sh in autoconf \"$srcdir\"/autoconf" >&2;}
-   { (exit 1); exit 1; }; }
-fi
-
-# These three variables are undocumented and unsupported,
-# and are intended to be withdrawn in a future Autoconf release.
-# They can cause serious problems if a builder's source tree is in a directory
-# whose full name contains unusual characters.
-ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
-ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
-ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
-
-
-
-################################################################################
-# Make sure we can run config.sub.
-$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
-  { { $as_echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5
-$as_echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;}
-   { (exit 1); exit 1; }; }
-
-{ $as_echo "$as_me:$LINENO: checking build system type" >&5
-$as_echo_n "checking build system type... " >&6; }
-if test "${ac_cv_build+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_build_alias=$build_alias
-test "x$ac_build_alias" = x &&
-  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
-test "x$ac_build_alias" = x &&
-  { { $as_echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
-$as_echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
-   { (exit 1); exit 1; }; }
-ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
-  { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5
-$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;}
-   { (exit 1); exit 1; }; }
-
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_build" >&5
-$as_echo "$ac_cv_build" >&6; }
-case $ac_cv_build in
-*-*-*) ;;
-*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical build" >&5
-$as_echo "$as_me: error: invalid value of canonical build" >&2;}
-   { (exit 1); exit 1; }; };;
-esac
-build=$ac_cv_build
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_build
-shift
-build_cpu=$1
-build_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-build_os=$*
-IFS=$ac_save_IFS
-case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
-
-
-{ $as_echo "$as_me:$LINENO: checking host system type" >&5
-$as_echo_n "checking host system type... " >&6; }
-if test "${ac_cv_host+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  if test "x$host_alias" = x; then
-  ac_cv_host=$ac_cv_build
-else
-  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
-    { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5
-$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;}
-   { (exit 1); exit 1; }; }
-fi
-
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_host" >&5
-$as_echo "$ac_cv_host" >&6; }
-case $ac_cv_host in
-*-*-*) ;;
-*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical host" >&5
-$as_echo "$as_me: error: invalid value of canonical host" >&2;}
-   { (exit 1); exit 1; }; };;
-esac
-host=$ac_cv_host
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_host
-shift
-host_cpu=$1
-host_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-host_os=$*
-IFS=$ac_save_IFS
-case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
-
-
-{ $as_echo "$as_me:$LINENO: checking target system type" >&5
-$as_echo_n "checking target system type... " >&6; }
-if test "${ac_cv_target+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  if test "x$target_alias" = x; then
-  ac_cv_target=$ac_cv_host
-else
-  ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` ||
-    { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $target_alias failed" >&5
-$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $target_alias failed" >&2;}
-   { (exit 1); exit 1; }; }
-fi
-
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_target" >&5
-$as_echo "$ac_cv_target" >&6; }
-case $ac_cv_target in
-*-*-*) ;;
-*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical target" >&5
-$as_echo "$as_me: error: invalid value of canonical target" >&2;}
-   { (exit 1); exit 1; }; };;
-esac
-target=$ac_cv_target
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_target
-shift
-target_cpu=$1
-target_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-target_os=$*
-IFS=$ac_save_IFS
-case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac
-
-
-# The aliases save the names the user supplied, while $host etc.
-# will get canonicalized.
-test -n "$target_alias" &&
-  test "$program_prefix$program_suffix$program_transform_name" = \
-    NONENONEs,x,x, &&
-  program_prefix=${target_alias}-
-
-case "$host_os" in
-       linux*)
-               CFLAGS="$CFLAGS"
-               COPTIMISE_FLAG="-O2"
-               CLDFLAGS="$CLDFLAGS -Wl,--version-script,.export.sym"
-               CLDWHOLEARCHIVE="-Wl,-whole-archive"
-               CLDNOWHOLEARCHIVE="-Wl,-no-whole-archive"
-               LDDEPS="$LDDEPS .export.sym"
-               LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
-               LIB_SUFFIX=so
-               DEVMAPPER=yes
-               ODIRECT=yes
-               DM_IOCTLS=yes
-               SELINUX=yes
-               CLUSTER=internal
-               FSADM=yes
-               ;;
-       darwin*)
-               CFLAGS="$CFLAGS -no-cpp-precomp -fno-common"
-               COPTIMISE_FLAG="-O2"
-               CLDFLAGS="$CLDFLAGS"
-               CLDWHOLEARCHIVE="-all_load"
-               CLDNOWHOLEARCHIVE=
-               LIB_SUFFIX=dylib
-               DEVMAPPER=yes
-               ODIRECT=no
-               DM_IOCTLS=no
-               SELINUX=no
-               CLUSTER=none
-               FSADM=no
-               ;;
-esac
-
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5
-$as_echo_n "checking for a sed that does not truncate output... " >&6; }
-if test "${ac_cv_path_SED+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-            ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
-     for ac_i in 1 2 3 4 5 6 7; do
-       ac_script="$ac_script$as_nl$ac_script"
-     done
-     echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
-     $as_unset ac_script || ac_script=
-     if test -z "$SED"; then
-  ac_path_SED_found=false
-  # Loop through the user's path and test for each of PROGNAME-LIST
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_prog in sed gsed; do
-    for ac_exec_ext in '' $ac_executable_extensions; do
-      ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
-      { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue
-# Check for GNU ac_path_SED and select it if it is found.
-  # Check for GNU $ac_path_SED
-case `"$ac_path_SED" --version 2>&1` in
-*GNU*)
-  ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
-*)
-  ac_count=0
-  $as_echo_n 0123456789 >"conftest.in"
-  while :
-  do
-    cat "conftest.in" "conftest.in" >"conftest.tmp"
-    mv "conftest.tmp" "conftest.in"
-    cp "conftest.in" "conftest.nl"
-    $as_echo '' >> "conftest.nl"
-    "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
-    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
-    ac_count=`expr $ac_count + 1`
-    if test $ac_count -gt ${ac_path_SED_max-0}; then
-      # Best one so far, save it but keep looking for a better one
-      ac_cv_path_SED="$ac_path_SED"
-      ac_path_SED_max=$ac_count
-    fi
-    # 10*(2^10) chars as input seems more than enough
-    test $ac_count -gt 10 && break
-  done
-  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
-      $ac_path_SED_found && break 3
-    done
-  done
-done
-IFS=$as_save_IFS
-  if test -z "$ac_cv_path_SED"; then
-    { { $as_echo "$as_me:$LINENO: error: no acceptable sed could be found in \$PATH" >&5
-$as_echo "$as_me: error: no acceptable sed could be found in \$PATH" >&2;}
-   { (exit 1); exit 1; }; }
-  fi
-else
-  ac_cv_path_SED=$SED
-fi
-
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_SED" >&5
-$as_echo "$ac_cv_path_SED" >&6; }
- SED="$ac_cv_path_SED"
-  rm -f conftest.sed
-
-for ac_prog in gawk mawk nawk awk
-do
-  # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_AWK+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$AWK"; then
-  ac_cv_prog_AWK="$AWK" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_prog_AWK="$ac_prog"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
-
-fi
-fi
-AWK=$ac_cv_prog_AWK
-if test -n "$AWK"; then
-  { $as_echo "$as_me:$LINENO: result: $AWK" >&5
-$as_echo "$AWK" >&6; }
-else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-  test -n "$AWK" && break
-done
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}gcc; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$CC"; then
-  ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_prog_CC="${ac_tool_prefix}gcc"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
-  { $as_echo "$as_me:$LINENO: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_CC"; then
-  ac_ct_CC=$CC
-  # Extract the first word of "gcc", so it can be a program name with args.
-set dummy gcc; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_CC"; then
-  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_prog_ac_ct_CC="gcc"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
-  { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
-$as_echo "$ac_ct_CC" >&6; }
-else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_CC" = x; then
-    CC=""
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    CC=$ac_ct_CC
-  fi
-else
-  CC="$ac_cv_prog_CC"
-fi
-
-if test -z "$CC"; then
-          if test -n "$ac_tool_prefix"; then
-    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}cc; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$CC"; then
-  ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_prog_CC="${ac_tool_prefix}cc"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
-  { $as_echo "$as_me:$LINENO: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-  fi
-fi
-if test -z "$CC"; then
-  # Extract the first word of "cc", so it can be a program name with args.
-set dummy cc; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$CC"; then
-  ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-  ac_prog_rejected=no
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
-       ac_prog_rejected=yes
-       continue
-     fi
-    ac_cv_prog_CC="cc"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
-
-if test $ac_prog_rejected = yes; then
-  # We found a bogon in the path, so make sure we never use it.
-  set dummy $ac_cv_prog_CC
-  shift
-  if test $# != 0; then
-    # We chose a different compiler from the bogus one.
-    # However, it has the same basename, so the bogon will be chosen
-    # first if we set CC to just the basename; use the full file name.
-    shift
-    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
-  fi
-fi
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
-  { $as_echo "$as_me:$LINENO: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$CC"; then
-  if test -n "$ac_tool_prefix"; then
-  for ac_prog in cl.exe
-  do
-    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
-set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$CC"; then
-  ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
-  { $as_echo "$as_me:$LINENO: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-    test -n "$CC" && break
-  done
-fi
-if test -z "$CC"; then
-  ac_ct_CC=$CC
-  for ac_prog in cl.exe
-do
-  # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_CC"; then
-  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_prog_ac_ct_CC="$ac_prog"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
-  { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
-$as_echo "$ac_ct_CC" >&6; }
-else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-  test -n "$ac_ct_CC" && break
-done
-
-  if test "x$ac_ct_CC" = x; then
-    CC=""
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    CC=$ac_ct_CC
-  fi
-fi
-
-fi
-
-
-test -z "$CC" && { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-{ { $as_echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
-See \`config.log' for more details." >&5
-$as_echo "$as_me: error: no acceptable C compiler found in \$PATH
-See \`config.log' for more details." >&2;}
-   { (exit 1); exit 1; }; }; }
-
-# Provide some information about the compiler.
-$as_echo "$as_me:$LINENO: checking for C compiler version" >&5
-set X $ac_compile
-ac_compiler=$2
-{ (ac_try="$ac_compiler --version >&5"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compiler --version >&5") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
-{ (ac_try="$ac_compiler -v >&5"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compiler -v >&5") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
-{ (ac_try="$ac_compiler -V >&5"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compiler -V >&5") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
-
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-ac_clean_files_save=$ac_clean_files
-ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
-# Try to create an executable without -o first, disregard a.out.
-# It will help us diagnose broken compilers, and finding out an intuition
-# of exeext.
-{ $as_echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
-$as_echo_n "checking for C compiler default output file name... " >&6; }
-ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
-
-# The possible output files:
-ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
-
-ac_rmfiles=
-for ac_file in $ac_files
-do
-  case $ac_file in
-    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
-    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
-  esac
-done
-rm -f $ac_rmfiles
-
-if { (ac_try="$ac_link_default"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link_default") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
-# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
-# in a Makefile.  We should not override ac_cv_exeext if it was cached,
-# so that the user can short-circuit this test for compilers unknown to
-# Autoconf.
-for ac_file in $ac_files ''
-do
-  test -f "$ac_file" || continue
-  case $ac_file in
-    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
-       ;;
-    [ab].out )
-       # We found the default executable, but exeext='' is most
-       # certainly right.
-       break;;
-    *.* )
-        if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
-       then :; else
-          ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
-       fi
-       # We set ac_cv_exeext here because the later test for it is not
-       # safe: cross compilers may not add the suffix if given an `-o'
-       # argument, so we may need to know it at that point already.
-       # Even if this section looks crufty: it has the advantage of
-       # actually working.
-       break;;
-    * )
-       break;;
-  esac
-done
-test "$ac_cv_exeext" = no && ac_cv_exeext=
-
-else
-  ac_file=''
-fi
-
-{ $as_echo "$as_me:$LINENO: result: $ac_file" >&5
-$as_echo "$ac_file" >&6; }
-if test -z "$ac_file"; then
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-{ { $as_echo "$as_me:$LINENO: error: C compiler cannot create executables
-See \`config.log' for more details." >&5
-$as_echo "$as_me: error: C compiler cannot create executables
-See \`config.log' for more details." >&2;}
-   { (exit 77); exit 77; }; }; }
-fi
-
-ac_exeext=$ac_cv_exeext
-
-# Check that the compiler produces executables we can run.  If not, either
-# the compiler is broken, or we cross compile.
-{ $as_echo "$as_me:$LINENO: checking whether the C compiler works" >&5
-$as_echo_n "checking whether the C compiler works... " >&6; }
-# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
-# If not cross compiling, check that we can run a simple program.
-if test "$cross_compiling" != yes; then
-  if { ac_try='./$ac_file'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-    cross_compiling=no
-  else
-    if test "$cross_compiling" = maybe; then
-       cross_compiling=yes
-    else
-       { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-{ { $as_echo "$as_me:$LINENO: error: cannot run C compiled programs.
-If you meant to cross compile, use \`--host'.
-See \`config.log' for more details." >&5
-$as_echo "$as_me: error: cannot run C compiled programs.
-If you meant to cross compile, use \`--host'.
-See \`config.log' for more details." >&2;}
-   { (exit 1); exit 1; }; }; }
-    fi
-  fi
-fi
-{ $as_echo "$as_me:$LINENO: result: yes" >&5
-$as_echo "yes" >&6; }
-
-rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
-ac_clean_files=$ac_clean_files_save
-# Check that the compiler produces executables we can run.  If not, either
-# the compiler is broken, or we cross compile.
-{ $as_echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
-$as_echo_n "checking whether we are cross compiling... " >&6; }
-{ $as_echo "$as_me:$LINENO: result: $cross_compiling" >&5
-$as_echo "$cross_compiling" >&6; }
-
-{ $as_echo "$as_me:$LINENO: checking for suffix of executables" >&5
-$as_echo_n "checking for suffix of executables... " >&6; }
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  # If both `conftest.exe' and `conftest' are `present' (well, observable)
-# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
-# work properly (i.e., refer to `conftest.exe'), while it won't with
-# `rm'.
-for ac_file in conftest.exe conftest conftest.*; do
-  test -f "$ac_file" || continue
-  case $ac_file in
-    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
-    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
-         break;;
-    * ) break;;
-  esac
-done
-else
-  { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
-See \`config.log' for more details." >&5
-$as_echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
-See \`config.log' for more details." >&2;}
-   { (exit 1); exit 1; }; }; }
-fi
-
-rm -f conftest$ac_cv_exeext
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
-$as_echo "$ac_cv_exeext" >&6; }
-
-rm -f conftest.$ac_ext
-EXEEXT=$ac_cv_exeext
-ac_exeext=$EXEEXT
-{ $as_echo "$as_me:$LINENO: checking for suffix of object files" >&5
-$as_echo_n "checking for suffix of object files... " >&6; }
-if test "${ac_cv_objext+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.o conftest.obj
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  for ac_file in conftest.o conftest.obj conftest.*; do
-  test -f "$ac_file" || continue;
-  case $ac_file in
-    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
-    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
-       break;;
-  esac
-done
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
-See \`config.log' for more details." >&5
-$as_echo "$as_me: error: cannot compute suffix of object files: cannot compile
-See \`config.log' for more details." >&2;}
-   { (exit 1); exit 1; }; }; }
-fi
-
-rm -f conftest.$ac_cv_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
-$as_echo "$ac_cv_objext" >&6; }
-OBJEXT=$ac_cv_objext
-ac_objext=$OBJEXT
-{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
-$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
-if test "${ac_cv_c_compiler_gnu+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-
-int
-main ()
-{
-#ifndef __GNUC__
-       choke me
-#endif
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_compiler_gnu=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_compiler_gnu=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-ac_cv_c_compiler_gnu=$ac_compiler_gnu
-
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
-$as_echo "$ac_cv_c_compiler_gnu" >&6; }
-if test $ac_compiler_gnu = yes; then
-  GCC=yes
-else
-  GCC=
-fi
-ac_test_CFLAGS=${CFLAGS+set}
-ac_save_CFLAGS=$CFLAGS
-{ $as_echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
-$as_echo_n "checking whether $CC accepts -g... " >&6; }
-if test "${ac_cv_prog_cc_g+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_save_c_werror_flag=$ac_c_werror_flag
-   ac_c_werror_flag=yes
-   ac_cv_prog_cc_g=no
-   CFLAGS="-g"
-   cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_prog_cc_g=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       CFLAGS=""
-      cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  :
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_c_werror_flag=$ac_save_c_werror_flag
-        CFLAGS="-g"
-        cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_prog_cc_g=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-   ac_c_werror_flag=$ac_save_c_werror_flag
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
-$as_echo "$ac_cv_prog_cc_g" >&6; }
-if test "$ac_test_CFLAGS" = set; then
-  CFLAGS=$ac_save_CFLAGS
-elif test $ac_cv_prog_cc_g = yes; then
-  if test "$GCC" = yes; then
-    CFLAGS="-g -O2"
-  else
-    CFLAGS="-g"
-  fi
-else
-  if test "$GCC" = yes; then
-    CFLAGS="-O2"
-  else
-    CFLAGS=
-  fi
-fi
-{ $as_echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
-$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
-if test "${ac_cv_prog_cc_c89+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_cv_prog_cc_c89=no
-ac_save_CC=$CC
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <stdarg.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
-struct buf { int x; };
-FILE * (*rcsopen) (struct buf *, struct stat *, int);
-static char *e (p, i)
-     char **p;
-     int i;
-{
-  return p[i];
-}
-static char *f (char * (*g) (char **, int), char **p, ...)
-{
-  char *s;
-  va_list v;
-  va_start (v,p);
-  s = g (p, va_arg (v,int));
-  va_end (v);
-  return s;
-}
-
-/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
-   function prototypes and stuff, but not '\xHH' hex character constants.
-   These don't provoke an error unfortunately, instead are silently treated
-   as 'x'.  The following induces an error, until -std is added to get
-   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
-   array size at least.  It's necessary to write '\x00'==0 to get something
-   that's true only with -std.  */
-int osf4_cc_array ['\x00' == 0 ? 1 : -1];
-
-/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
-   inside strings and character constants.  */
-#define FOO(x) 'x'
-int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
-
-int test (int i, double x);
-struct s1 {int (*f) (int a);};
-struct s2 {int (*f) (double a);};
-int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
-int argc;
-char **argv;
-int
-main ()
-{
-return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
-  ;
-  return 0;
-}
-_ACEOF
-for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
-       -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
-do
-  CC="$ac_save_CC $ac_arg"
-  rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_prog_cc_c89=$ac_arg
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
-fi
-
-rm -f core conftest.err conftest.$ac_objext
-  test "x$ac_cv_prog_cc_c89" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-
-fi
-# AC_CACHE_VAL
-case "x$ac_cv_prog_cc_c89" in
-  x)
-    { $as_echo "$as_me:$LINENO: result: none needed" >&5
-$as_echo "none needed" >&6; } ;;
-  xno)
-    { $as_echo "$as_me:$LINENO: result: unsupported" >&5
-$as_echo "unsupported" >&6; } ;;
-  *)
-    CC="$CC $ac_cv_prog_cc_c89"
-    { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
-$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
-esac
-
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-{ $as_echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
-$as_echo_n "checking how to run the C preprocessor... " >&6; }
-# On Suns, sometimes $CPP names a directory.
-if test -n "$CPP" && test -d "$CPP"; then
-  CPP=
-fi
-if test -z "$CPP"; then
-  if test "${ac_cv_prog_CPP+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-      # Double quotes because CPP needs to be expanded
-    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
-    do
-      ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
-do
-  # Use a header file that comes with gcc, so configuring glibc
-  # with a fresh cross-compiler works.
-  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-  # <limits.h> exists even on freestanding compilers.
-  # On the NeXT, cc -E runs the code through the compiler's parser,
-  # not just through cpp. "Syntax error" is here to catch this case.
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-                    Syntax error
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  :
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  # Broken: fails on valid input.
-continue
-fi
-
-rm -f conftest.err conftest.$ac_ext
-
-  # OK, works on sane cases.  Now check whether nonexistent headers
-  # can be detected and how.
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <ac_nonexistent.h>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  # Broken: success on invalid input.
-continue
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  # Passes both tests.
-ac_preproc_ok=:
-break
-fi
-
-rm -f conftest.err conftest.$ac_ext
-
-done
-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then
-  break
-fi
-
-    done
-    ac_cv_prog_CPP=$CPP
-
-fi
-  CPP=$ac_cv_prog_CPP
-else
-  ac_cv_prog_CPP=$CPP
-fi
-{ $as_echo "$as_me:$LINENO: result: $CPP" >&5
-$as_echo "$CPP" >&6; }
-ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
-do
-  # Use a header file that comes with gcc, so configuring glibc
-  # with a fresh cross-compiler works.
-  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-  # <limits.h> exists even on freestanding compilers.
-  # On the NeXT, cc -E runs the code through the compiler's parser,
-  # not just through cpp. "Syntax error" is here to catch this case.
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-                    Syntax error
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  :
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  # Broken: fails on valid input.
-continue
-fi
-
-rm -f conftest.err conftest.$ac_ext
-
-  # OK, works on sane cases.  Now check whether nonexistent headers
-  # can be detected and how.
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <ac_nonexistent.h>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  # Broken: success on invalid input.
-continue
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  # Passes both tests.
-ac_preproc_ok=:
-break
-fi
-
-rm -f conftest.err conftest.$ac_ext
-
-done
-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then
-  :
-else
-  { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-{ { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
-See \`config.log' for more details." >&5
-$as_echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
-See \`config.log' for more details." >&2;}
-   { (exit 1); exit 1; }; }; }
-fi
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
-{ $as_echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5
-$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
-if test "${ac_cv_path_GREP+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  if test -z "$GREP"; then
-  ac_path_GREP_found=false
-  # Loop through the user's path and test for each of PROGNAME-LIST
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_prog in grep ggrep; do
-    for ac_exec_ext in '' $ac_executable_extensions; do
-      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
-      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
-# Check for GNU ac_path_GREP and select it if it is found.
-  # Check for GNU $ac_path_GREP
-case `"$ac_path_GREP" --version 2>&1` in
-*GNU*)
-  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
-*)
-  ac_count=0
-  $as_echo_n 0123456789 >"conftest.in"
-  while :
-  do
-    cat "conftest.in" "conftest.in" >"conftest.tmp"
-    mv "conftest.tmp" "conftest.in"
-    cp "conftest.in" "conftest.nl"
-    $as_echo 'GREP' >> "conftest.nl"
-    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
-    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
-    ac_count=`expr $ac_count + 1`
-    if test $ac_count -gt ${ac_path_GREP_max-0}; then
-      # Best one so far, save it but keep looking for a better one
-      ac_cv_path_GREP="$ac_path_GREP"
-      ac_path_GREP_max=$ac_count
-    fi
-    # 10*(2^10) chars as input seems more than enough
-    test $ac_count -gt 10 && break
-  done
-  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
-      $ac_path_GREP_found && break 3
-    done
-  done
-done
-IFS=$as_save_IFS
-  if test -z "$ac_cv_path_GREP"; then
-    { { $as_echo "$as_me:$LINENO: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
-$as_echo "$as_me: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
-   { (exit 1); exit 1; }; }
-  fi
-else
-  ac_cv_path_GREP=$GREP
-fi
-
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5
-$as_echo "$ac_cv_path_GREP" >&6; }
- GREP="$ac_cv_path_GREP"
-
-
-{ $as_echo "$as_me:$LINENO: checking for egrep" >&5
-$as_echo_n "checking for egrep... " >&6; }
-if test "${ac_cv_path_EGREP+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
-   then ac_cv_path_EGREP="$GREP -E"
-   else
-     if test -z "$EGREP"; then
-  ac_path_EGREP_found=false
-  # Loop through the user's path and test for each of PROGNAME-LIST
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_prog in egrep; do
-    for ac_exec_ext in '' $ac_executable_extensions; do
-      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
-      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
-# Check for GNU ac_path_EGREP and select it if it is found.
-  # Check for GNU $ac_path_EGREP
-case `"$ac_path_EGREP" --version 2>&1` in
-*GNU*)
-  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
-*)
-  ac_count=0
-  $as_echo_n 0123456789 >"conftest.in"
-  while :
-  do
-    cat "conftest.in" "conftest.in" >"conftest.tmp"
-    mv "conftest.tmp" "conftest.in"
-    cp "conftest.in" "conftest.nl"
-    $as_echo 'EGREP' >> "conftest.nl"
-    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
-    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
-    ac_count=`expr $ac_count + 1`
-    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
-      # Best one so far, save it but keep looking for a better one
-      ac_cv_path_EGREP="$ac_path_EGREP"
-      ac_path_EGREP_max=$ac_count
-    fi
-    # 10*(2^10) chars as input seems more than enough
-    test $ac_count -gt 10 && break
-  done
-  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
-      $ac_path_EGREP_found && break 3
-    done
-  done
-done
-IFS=$as_save_IFS
-  if test -z "$ac_cv_path_EGREP"; then
-    { { $as_echo "$as_me:$LINENO: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
-$as_echo "$as_me: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
-   { (exit 1); exit 1; }; }
-  fi
-else
-  ac_cv_path_EGREP=$EGREP
-fi
-
-   fi
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5
-$as_echo "$ac_cv_path_EGREP" >&6; }
- EGREP="$ac_cv_path_EGREP"
-
-
-if test $ac_cv_c_compiler_gnu = yes; then
-    { $as_echo "$as_me:$LINENO: checking whether $CC needs -traditional" >&5
-$as_echo_n "checking whether $CC needs -traditional... " >&6; }
-if test "${ac_cv_prog_gcc_traditional+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-    ac_pattern="Autoconf.*'x'"
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <sgtty.h>
-Autoconf TIOCGETP
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  $EGREP "$ac_pattern" >/dev/null 2>&1; then
-  ac_cv_prog_gcc_traditional=yes
-else
-  ac_cv_prog_gcc_traditional=no
-fi
-rm -f conftest*
-
-
-  if test $ac_cv_prog_gcc_traditional = no; then
-    cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <termio.h>
-Autoconf TCGETA
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  $EGREP "$ac_pattern" >/dev/null 2>&1; then
-  ac_cv_prog_gcc_traditional=yes
-fi
-rm -f conftest*
-
-  fi
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_gcc_traditional" >&5
-$as_echo "$ac_cv_prog_gcc_traditional" >&6; }
-  if test $ac_cv_prog_gcc_traditional = yes; then
-    CC="$CC -traditional"
-  fi
-fi
-
-# Find a good install program.  We prefer a C program (faster),
-# so one script is as good as another.  But avoid the broken or
-# incompatible versions:
-# SysV /etc/install, /usr/sbin/install
-# SunOS /usr/etc/install
-# IRIX /sbin/install
-# AIX /bin/install
-# AmigaOS /C/install, which installs bootblocks on floppy discs
-# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
-# AFS /usr/afsws/bin/install, which mishandles nonexistent args
-# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
-# OS/2's system install, which has a completely different semantic
-# ./install, which can be erroneously created by make from ./install.sh.
-# Reject install programs that cannot install multiple files.
-{ $as_echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
-$as_echo_n "checking for a BSD-compatible install... " >&6; }
-if test -z "$INSTALL"; then
-if test "${ac_cv_path_install+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  # Account for people who put trailing slashes in PATH elements.
-case $as_dir/ in
-  ./ | .// | /cC/* | \
-  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
-  ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
-  /usr/ucb/* ) ;;
-  *)
-    # OSF1 and SCO ODT 3.0 have their own names for install.
-    # Don't use installbsd from OSF since it installs stuff as root
-    # by default.
-    for ac_prog in ginstall scoinst install; do
-      for ac_exec_ext in '' $ac_executable_extensions; do
-       if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
-         if test $ac_prog = install &&
-           grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
-           # AIX install.  It has an incompatible calling convention.
-           :
-         elif test $ac_prog = install &&
-           grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
-           # program-specific install script used by HP pwplus--don't use.
-           :
-         else
-           rm -rf conftest.one conftest.two conftest.dir
-           echo one > conftest.one
-           echo two > conftest.two
-           mkdir conftest.dir
-           if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
-             test -s conftest.one && test -s conftest.two &&
-             test -s conftest.dir/conftest.one &&
-             test -s conftest.dir/conftest.two
-           then
-             ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
-             break 3
-           fi
-         fi
-       fi
-      done
-    done
-    ;;
-esac
-
-done
-IFS=$as_save_IFS
-
-rm -rf conftest.one conftest.two conftest.dir
-
-fi
-  if test "${ac_cv_path_install+set}" = set; then
-    INSTALL=$ac_cv_path_install
-  else
-    # As a last resort, use the slow shell script.  Don't cache a
-    # value for INSTALL within a source directory, because that will
-    # break other packages using the cache if that directory is
-    # removed, or if the value is a relative name.
-    INSTALL=$ac_install_sh
-  fi
-fi
-{ $as_echo "$as_me:$LINENO: result: $INSTALL" >&5
-$as_echo "$INSTALL" >&6; }
-
-# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
-# It thinks the first close brace ends the variable substitution.
-test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
-
-test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
-
-test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
-
-{ $as_echo "$as_me:$LINENO: checking whether ln -s works" >&5
-$as_echo_n "checking whether ln -s works... " >&6; }
-LN_S=$as_ln_s
-if test "$LN_S" = "ln -s"; then
-  { $as_echo "$as_me:$LINENO: result: yes" >&5
-$as_echo "yes" >&6; }
-else
-  { $as_echo "$as_me:$LINENO: result: no, using $LN_S" >&5
-$as_echo "no, using $LN_S" >&6; }
-fi
-
-{ $as_echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
-$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
-set x ${MAKE-make}
-ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
-if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.make <<\_ACEOF
-SHELL = /bin/sh
-all:
-       @echo '@@@%%%=$(MAKE)=@@@%%%'
-_ACEOF
-# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
-case `${MAKE-make} -f conftest.make 2>/dev/null` in
-  *@@@%%%=?*=@@@%%%*)
-    eval ac_cv_prog_make_${ac_make}_set=yes;;
-  *)
-    eval ac_cv_prog_make_${ac_make}_set=no;;
-esac
-rm -f conftest.make
-fi
-if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
-  { $as_echo "$as_me:$LINENO: result: yes" >&5
-$as_echo "yes" >&6; }
-  SET_MAKE=
-else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-  SET_MAKE="MAKE=${MAKE-make}"
-fi
-
-{ $as_echo "$as_me:$LINENO: checking for a thread-safe mkdir -p" >&5
-$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
-if test -z "$MKDIR_P"; then
-  if test "${ac_cv_path_mkdir+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_prog in mkdir gmkdir; do
-        for ac_exec_ext in '' $ac_executable_extensions; do
-          { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
-          case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
-            'mkdir (GNU coreutils) '* | \
-            'mkdir (coreutils) '* | \
-            'mkdir (fileutils) '4.1*)
-              ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
-              break 3;;
-          esac
-        done
-       done
-done
-IFS=$as_save_IFS
-
-fi
-
-  if test "${ac_cv_path_mkdir+set}" = set; then
-    MKDIR_P="$ac_cv_path_mkdir -p"
-  else
-    # As a last resort, use the slow shell script.  Don't cache a
-    # value for MKDIR_P within a source directory, because that will
-    # break other packages using the cache if that directory is
-    # removed, or if the value is a relative name.
-    test -d ./--version && rmdir ./--version
-    MKDIR_P="$ac_install_sh -d"
-  fi
-fi
-{ $as_echo "$as_me:$LINENO: result: $MKDIR_P" >&5
-$as_echo "$MKDIR_P" >&6; }
-
-if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
-set dummy ${ac_tool_prefix}ranlib; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_RANLIB+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$RANLIB"; then
-  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
-
-fi
-fi
-RANLIB=$ac_cv_prog_RANLIB
-if test -n "$RANLIB"; then
-  { $as_echo "$as_me:$LINENO: result: $RANLIB" >&5
-$as_echo "$RANLIB" >&6; }
-else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_RANLIB"; then
-  ac_ct_RANLIB=$RANLIB
-  # Extract the first word of "ranlib", so it can be a program name with args.
-set dummy ranlib; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_RANLIB"; then
-  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_prog_ac_ct_RANLIB="ranlib"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
-if test -n "$ac_ct_RANLIB"; then
-  { $as_echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
-$as_echo "$ac_ct_RANLIB" >&6; }
-else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_RANLIB" = x; then
-    RANLIB=":"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    RANLIB=$ac_ct_RANLIB
-  fi
-else
-  RANLIB="$ac_cv_prog_RANLIB"
-fi
-
-# Extract the first word of "cflow", so it can be a program name with args.
-set dummy cflow; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_path_CFLOW_CMD+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  case $CFLOW_CMD in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_CFLOW_CMD="$CFLOW_CMD" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_path_CFLOW_CMD="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
-
-  ;;
-esac
-fi
-CFLOW_CMD=$ac_cv_path_CFLOW_CMD
-if test -n "$CFLOW_CMD"; then
-  { $as_echo "$as_me:$LINENO: result: $CFLOW_CMD" >&5
-$as_echo "$CFLOW_CMD" >&6; }
-else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-# Extract the first word of "cscope", so it can be a program name with args.
-set dummy cscope; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_path_CSCOPE_CMD+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  case $CSCOPE_CMD in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_CSCOPE_CMD="$CSCOPE_CMD" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_path_CSCOPE_CMD="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
-
-  ;;
-esac
-fi
-CSCOPE_CMD=$ac_cv_path_CSCOPE_CMD
-if test -n "$CSCOPE_CMD"; then
-  { $as_echo "$as_me:$LINENO: result: $CSCOPE_CMD" >&5
-$as_echo "$CSCOPE_CMD" >&6; }
-else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-
-################################################################################
-
-
-
-
-
-ac_header_dirent=no
-for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do
-  as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh`
-{ $as_echo "$as_me:$LINENO: checking for $ac_hdr that defines DIR" >&5
-$as_echo_n "checking for $ac_hdr that defines DIR... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <sys/types.h>
-#include <$ac_hdr>
-
-int
-main ()
-{
-if ((DIR *) 0)
-return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  eval "$as_ac_Header=yes"
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       eval "$as_ac_Header=no"
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1
-_ACEOF
-
-ac_header_dirent=$ac_hdr; break
-fi
-
-done
-# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
-if test $ac_header_dirent = dirent.h; then
-  { $as_echo "$as_me:$LINENO: checking for library containing opendir" >&5
-$as_echo_n "checking for library containing opendir... " >&6; }
-if test "${ac_cv_search_opendir+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_func_search_save_LIBS=$LIBS
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char opendir ();
-int
-main ()
-{
-return opendir ();
-  ;
-  return 0;
-}
-_ACEOF
-for ac_lib in '' dir; do
-  if test -z "$ac_lib"; then
-    ac_res="none required"
-  else
-    ac_res=-l$ac_lib
-    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
-  fi
-  rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_search_opendir=$ac_res
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
-fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext
-  if test "${ac_cv_search_opendir+set}" = set; then
-  break
-fi
-done
-if test "${ac_cv_search_opendir+set}" = set; then
-  :
-else
-  ac_cv_search_opendir=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5
-$as_echo "$ac_cv_search_opendir" >&6; }
-ac_res=$ac_cv_search_opendir
-if test "$ac_res" != no; then
-  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-fi
-
-else
-  { $as_echo "$as_me:$LINENO: checking for library containing opendir" >&5
-$as_echo_n "checking for library containing opendir... " >&6; }
-if test "${ac_cv_search_opendir+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_func_search_save_LIBS=$LIBS
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char opendir ();
-int
-main ()
-{
-return opendir ();
-  ;
-  return 0;
-}
-_ACEOF
-for ac_lib in '' x; do
-  if test -z "$ac_lib"; then
-    ac_res="none required"
-  else
-    ac_res=-l$ac_lib
-    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
-  fi
-  rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_search_opendir=$ac_res
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
-fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext
-  if test "${ac_cv_search_opendir+set}" = set; then
-  break
-fi
-done
-if test "${ac_cv_search_opendir+set}" = set; then
-  :
-else
-  ac_cv_search_opendir=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5
-$as_echo "$ac_cv_search_opendir" >&6; }
-ac_res=$ac_cv_search_opendir
-if test "$ac_res" != no; then
-  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-fi
-
-fi
-
-{ $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5
-$as_echo_n "checking for ANSI C header files... " >&6; }
-if test "${ac_cv_header_stdc+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <float.h>
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_header_stdc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_header_stdc=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-if test $ac_cv_header_stdc = yes; then
-  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <string.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  $EGREP "memchr" >/dev/null 2>&1; then
-  :
-else
-  ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
-  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <stdlib.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  $EGREP "free" >/dev/null 2>&1; then
-  :
-else
-  ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
-  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
-  if test "$cross_compiling" = yes; then
-  :
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <ctype.h>
-#include <stdlib.h>
-#if ((' ' & 0x0FF) == 0x020)
-# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
-# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
-#else
-# define ISLOWER(c) \
-                  (('a' <= (c) && (c) <= 'i') \
-                    || ('j' <= (c) && (c) <= 'r') \
-                    || ('s' <= (c) && (c) <= 'z'))
-# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
-#endif
-
-#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
-int
-main ()
-{
-  int i;
-  for (i = 0; i < 256; i++)
-    if (XOR (islower (i), ISLOWER (i))
-       || toupper (i) != TOUPPER (i))
-      return 2;
-  return 0;
-}
-_ACEOF
-rm -f conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  :
-else
-  $as_echo "$as_me: program exited with status $ac_status" >&5
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-( exit $ac_status )
-ac_cv_header_stdc=no
-fi
-rm -rf conftest.dSYM
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
-fi
-
-
-fi
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
-$as_echo "$ac_cv_header_stdc" >&6; }
-if test $ac_cv_header_stdc = yes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define STDC_HEADERS 1
-_ACEOF
-
-fi
-
-# On IRIX 5.3, sys/types and inttypes.h are conflicting.
-
-
-
-
-
-
-
-
-
-for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
-                 inttypes.h stdint.h unistd.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  eval "$as_ac_Header=yes"
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       eval "$as_ac_Header=no"
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-fi
-
-done
-
-
-{ $as_echo "$as_me:$LINENO: checking whether sys/types.h defines makedev" >&5
-$as_echo_n "checking whether sys/types.h defines makedev... " >&6; }
-if test "${ac_cv_header_sys_types_h_makedev+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <sys/types.h>
-int
-main ()
-{
-return makedev(0, 0);
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_header_sys_types_h_makedev=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_header_sys_types_h_makedev=no
-fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_sys_types_h_makedev" >&5
-$as_echo "$ac_cv_header_sys_types_h_makedev" >&6; }
-
-if test $ac_cv_header_sys_types_h_makedev = no; then
-if test "${ac_cv_header_sys_mkdev_h+set}" = set; then
-  { $as_echo "$as_me:$LINENO: checking for sys/mkdev.h" >&5
-$as_echo_n "checking for sys/mkdev.h... " >&6; }
-if test "${ac_cv_header_sys_mkdev_h+set}" = set; then
-  $as_echo_n "(cached) " >&6
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_sys_mkdev_h" >&5
-$as_echo "$ac_cv_header_sys_mkdev_h" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking sys/mkdev.h usability" >&5
-$as_echo_n "checking sys/mkdev.h usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <sys/mkdev.h>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_header_compiler=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking sys/mkdev.h presence" >&5
-$as_echo_n "checking sys/mkdev.h presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <sys/mkdev.h>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  ac_header_preproc=no
-fi
-
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: sys/mkdev.h: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: sys/mkdev.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: sys/mkdev.h: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: sys/mkdev.h: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: sys/mkdev.h: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: sys/mkdev.h: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: sys/mkdev.h:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: sys/mkdev.h:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: sys/mkdev.h: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: sys/mkdev.h: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: sys/mkdev.h:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: sys/mkdev.h:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: sys/mkdev.h: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: sys/mkdev.h: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: sys/mkdev.h: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: sys/mkdev.h: in the future, the compiler will take precedence" >&2;}
-
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for sys/mkdev.h" >&5
-$as_echo_n "checking for sys/mkdev.h... " >&6; }
-if test "${ac_cv_header_sys_mkdev_h+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_cv_header_sys_mkdev_h=$ac_header_preproc
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_sys_mkdev_h" >&5
-$as_echo "$ac_cv_header_sys_mkdev_h" >&6; }
-
-fi
-if test "x$ac_cv_header_sys_mkdev_h" = x""yes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define MAJOR_IN_MKDEV 1
-_ACEOF
-
-fi
-
-
-
-  if test $ac_cv_header_sys_mkdev_h = no; then
-    if test "${ac_cv_header_sys_sysmacros_h+set}" = set; then
-  { $as_echo "$as_me:$LINENO: checking for sys/sysmacros.h" >&5
-$as_echo_n "checking for sys/sysmacros.h... " >&6; }
-if test "${ac_cv_header_sys_sysmacros_h+set}" = set; then
-  $as_echo_n "(cached) " >&6
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_sys_sysmacros_h" >&5
-$as_echo "$ac_cv_header_sys_sysmacros_h" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking sys/sysmacros.h usability" >&5
-$as_echo_n "checking sys/sysmacros.h usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <sys/sysmacros.h>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_header_compiler=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking sys/sysmacros.h presence" >&5
-$as_echo_n "checking sys/sysmacros.h presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <sys/sysmacros.h>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  ac_header_preproc=no
-fi
-
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: sys/sysmacros.h: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: sys/sysmacros.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: sys/sysmacros.h: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: sys/sysmacros.h: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: sys/sysmacros.h: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: sys/sysmacros.h: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: sys/sysmacros.h:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: sys/sysmacros.h:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: sys/sysmacros.h: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: sys/sysmacros.h: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: sys/sysmacros.h:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: sys/sysmacros.h:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: sys/sysmacros.h: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: sys/sysmacros.h: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: sys/sysmacros.h: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: sys/sysmacros.h: in the future, the compiler will take precedence" >&2;}
-
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for sys/sysmacros.h" >&5
-$as_echo_n "checking for sys/sysmacros.h... " >&6; }
-if test "${ac_cv_header_sys_sysmacros_h+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_cv_header_sys_sysmacros_h=$ac_header_preproc
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_sys_sysmacros_h" >&5
-$as_echo "$ac_cv_header_sys_sysmacros_h" >&6; }
-
-fi
-if test "x$ac_cv_header_sys_sysmacros_h" = x""yes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define MAJOR_IN_SYSMACROS 1
-_ACEOF
-
-fi
-
-
-  fi
-fi
-
-{ $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5
-$as_echo_n "checking for ANSI C header files... " >&6; }
-if test "${ac_cv_header_stdc+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <float.h>
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_header_stdc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_header_stdc=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-if test $ac_cv_header_stdc = yes; then
-  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <string.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  $EGREP "memchr" >/dev/null 2>&1; then
-  :
-else
-  ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
-  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <stdlib.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  $EGREP "free" >/dev/null 2>&1; then
-  :
-else
-  ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
-  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
-  if test "$cross_compiling" = yes; then
-  :
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <ctype.h>
-#include <stdlib.h>
-#if ((' ' & 0x0FF) == 0x020)
-# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
-# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
-#else
-# define ISLOWER(c) \
-                  (('a' <= (c) && (c) <= 'i') \
-                    || ('j' <= (c) && (c) <= 'r') \
-                    || ('s' <= (c) && (c) <= 'z'))
-# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
-#endif
-
-#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
-int
-main ()
-{
-  int i;
-  for (i = 0; i < 256; i++)
-    if (XOR (islower (i), ISLOWER (i))
-       || toupper (i) != TOUPPER (i))
-      return 2;
-  return 0;
-}
-_ACEOF
-rm -f conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  :
-else
-  $as_echo "$as_me: program exited with status $ac_status" >&5
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-( exit $ac_status )
-ac_cv_header_stdc=no
-fi
-rm -rf conftest.dSYM
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
-fi
-
-
-fi
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
-$as_echo "$ac_cv_header_stdc" >&6; }
-if test $ac_cv_header_stdc = yes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define STDC_HEADERS 1
-_ACEOF
-
-fi
-
-{ $as_echo "$as_me:$LINENO: checking for sys/wait.h that is POSIX.1 compatible" >&5
-$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; }
-if test "${ac_cv_header_sys_wait_h+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <sys/types.h>
-#include <sys/wait.h>
-#ifndef WEXITSTATUS
-# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8)
-#endif
-#ifndef WIFEXITED
-# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
-#endif
-
-int
-main ()
-{
-  int s;
-  wait (&s);
-  s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_header_sys_wait_h=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_header_sys_wait_h=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_sys_wait_h" >&5
-$as_echo "$ac_cv_header_sys_wait_h" >&6; }
-if test $ac_cv_header_sys_wait_h = yes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_SYS_WAIT_H 1
-_ACEOF
-
-fi
-
-{ $as_echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5
-$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; }
-if test "${ac_cv_header_time+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <sys/types.h>
-#include <sys/time.h>
-#include <time.h>
-
-int
-main ()
-{
-if ((struct tm *) 0)
-return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_header_time=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_header_time=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5
-$as_echo "$ac_cv_header_time" >&6; }
-if test $ac_cv_header_time = yes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define TIME_WITH_SYS_TIME 1
-_ACEOF
-
-fi
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-for ac_header in locale.h stddef.h syslog.h sys/file.h sys/time.h assert.h \
-  langinfo.h libgen.h signal.h sys/mman.h sys/resource.h sys/utsname.h \
-  sys/wait.h time.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_header_compiler=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  ac_header_preproc=no
-fi
-
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
-
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  eval "$as_ac_Header=\$ac_header_preproc"
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-
-fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-else
-  { { $as_echo "$as_me:$LINENO: error: bailing out" >&5
-$as_echo "$as_me: error: bailing out" >&2;}
-   { (exit 1); exit 1; }; }
-fi
-
-done
-
-
-case "$host_os" in
-       linux*)
-
-
-
-for ac_header in asm/byteorder.h linux/fs.h malloc.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_header_compiler=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  ac_header_preproc=no
-fi
-
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
-
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  eval "$as_ac_Header=\$ac_header_preproc"
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-
-fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-else
-  { { $as_echo "$as_me:$LINENO: error: bailing out" >&5
-$as_echo "$as_me: error: bailing out" >&2;}
-   { (exit 1); exit 1; }; }
-fi
-
-done
- ;;
-       darwin*)
-
-
-for ac_header in machine/endian.h sys/disk.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_header_compiler=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  ac_header_preproc=no
-fi
-
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
-
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  eval "$as_ac_Header=\$ac_header_preproc"
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-
-fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-else
-  { { $as_echo "$as_me:$LINENO: error: bailing out" >&5
-$as_echo "$as_me: error: bailing out" >&2;}
-   { (exit 1); exit 1; }; }
-fi
-
-done
- ;;
-esac
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-for ac_header in ctype.h dirent.h errno.h fcntl.h getopt.h inttypes.h limits.h \
-  stdarg.h stdio.h stdlib.h string.h sys/ioctl.h sys/param.h sys/stat.h \
-  sys/types.h unistd.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_header_compiler=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  ac_header_preproc=no
-fi
-
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
-
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  eval "$as_ac_Header=\$ac_header_preproc"
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-
-fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-else
-  { { $as_echo "$as_me:$LINENO: error: bailing out" >&5
-$as_echo "$as_me: error: bailing out" >&2;}
-   { (exit 1); exit 1; }; }
-fi
-
-done
-
-
-
-for ac_header in termios.h sys/statvfs.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_header_compiler=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  ac_header_preproc=no
-fi
-
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
-
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  eval "$as_ac_Header=\$ac_header_preproc"
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-
-fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-fi
-
-done
-
-
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
-$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
-if test "${ac_cv_c_const+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-
-int
-main ()
-{
-/* FIXME: Include the comments suggested by Paul. */
-#ifndef __cplusplus
-  /* Ultrix mips cc rejects this.  */
-  typedef int charset[2];
-  const charset cs;
-  /* SunOS 4.1.1 cc rejects this.  */
-  char const *const *pcpcc;
-  char **ppc;
-  /* NEC SVR4.0.2 mips cc rejects this.  */
-  struct point {int x, y;};
-  static struct point const zero = {0,0};
-  /* AIX XL C 1.02.0.0 rejects this.
-     It does not let you subtract one const X* pointer from another in
-     an arm of an if-expression whose if-part is not a constant
-     expression */
-  const char *g = "string";
-  pcpcc = &g + (g ? g-g : 0);
-  /* HPUX 7.0 cc rejects these. */
-  ++pcpcc;
-  ppc = (char**) pcpcc;
-  pcpcc = (char const *const *) ppc;
-  { /* SCO 3.2v4 cc rejects this.  */
-    char *t;
-    char const *s = 0 ? (char *) 0 : (char const *) 0;
-
-    *t++ = 0;
-    if (s) return 0;
-  }
-  { /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
-    int x[] = {25, 17};
-    const int *foo = &x[0];
-    ++foo;
-  }
-  { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
-    typedef const int *iptr;
-    iptr p = 0;
-    ++p;
-  }
-  { /* AIX XL C 1.02.0.0 rejects this saying
-       "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
-    struct s { int j; const int *ap[3]; };
-    struct s *b; b->j = 5;
-  }
-  { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
-    const int foo = 10;
-    if (!foo) return 0;
-  }
-  return !cs[0] && !zero.x;
-#endif
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_c_const=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_c_const=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
-$as_echo "$ac_cv_c_const" >&6; }
-if test $ac_cv_c_const = no; then
-
-cat >>confdefs.h <<\_ACEOF
-#define const /**/
-_ACEOF
-
-fi
-
-{ $as_echo "$as_me:$LINENO: checking for inline" >&5
-$as_echo_n "checking for inline... " >&6; }
-if test "${ac_cv_c_inline+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_cv_c_inline=no
-for ac_kw in inline __inline__ __inline; do
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#ifndef __cplusplus
-typedef int foo_t;
-static $ac_kw foo_t static_foo () {return 0; }
-$ac_kw foo_t foo () {return 0; }
-#endif
-
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_c_inline=$ac_kw
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-  test "$ac_cv_c_inline" != no && break
-done
-
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5
-$as_echo "$ac_cv_c_inline" >&6; }
-
-
-case $ac_cv_c_inline in
-  inline | yes) ;;
-  *)
-    case $ac_cv_c_inline in
-      no) ac_val=;;
-      *) ac_val=$ac_cv_c_inline;;
-    esac
-    cat >>confdefs.h <<_ACEOF
-#ifndef __cplusplus
-#define inline $ac_val
-#endif
-_ACEOF
-    ;;
-esac
-
-{ $as_echo "$as_me:$LINENO: checking for struct stat.st_rdev" >&5
-$as_echo_n "checking for struct stat.st_rdev... " >&6; }
-if test "${ac_cv_member_struct_stat_st_rdev+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-static struct stat ac_aggr;
-if (ac_aggr.st_rdev)
-return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_member_struct_stat_st_rdev=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-static struct stat ac_aggr;
-if (sizeof ac_aggr.st_rdev)
-return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_member_struct_stat_st_rdev=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_member_struct_stat_st_rdev=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_rdev" >&5
-$as_echo "$ac_cv_member_struct_stat_st_rdev" >&6; }
-if test "x$ac_cv_member_struct_stat_st_rdev" = x""yes; then
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_STAT_ST_RDEV 1
-_ACEOF
-
-
-fi
-
-{ $as_echo "$as_me:$LINENO: checking for off_t" >&5
-$as_echo_n "checking for off_t... " >&6; }
-if test "${ac_cv_type_off_t+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_cv_type_off_t=no
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-if (sizeof (off_t))
-       return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-if (sizeof ((off_t)))
-         return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  :
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_type_off_t=yes
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_off_t" >&5
-$as_echo "$ac_cv_type_off_t" >&6; }
-if test "x$ac_cv_type_off_t" = x""yes; then
-  :
-else
-
-cat >>confdefs.h <<_ACEOF
-#define off_t long int
-_ACEOF
-
-fi
-
-{ $as_echo "$as_me:$LINENO: checking for pid_t" >&5
-$as_echo_n "checking for pid_t... " >&6; }
-if test "${ac_cv_type_pid_t+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_cv_type_pid_t=no
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-if (sizeof (pid_t))
-       return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-if (sizeof ((pid_t)))
-         return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  :
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_type_pid_t=yes
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_pid_t" >&5
-$as_echo "$ac_cv_type_pid_t" >&6; }
-if test "x$ac_cv_type_pid_t" = x""yes; then
-  :
-else
-
-cat >>confdefs.h <<_ACEOF
-#define pid_t int
-_ACEOF
-
-fi
-
-{ $as_echo "$as_me:$LINENO: checking return type of signal handlers" >&5
-$as_echo_n "checking return type of signal handlers... " >&6; }
-if test "${ac_cv_type_signal+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <sys/types.h>
-#include <signal.h>
-
-int
-main ()
-{
-return *(signal (0, 0)) (0) == 1;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_type_signal=int
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_type_signal=void
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5
-$as_echo "$ac_cv_type_signal" >&6; }
-
-cat >>confdefs.h <<_ACEOF
-#define RETSIGTYPE $ac_cv_type_signal
-_ACEOF
-
-
-{ $as_echo "$as_me:$LINENO: checking for size_t" >&5
-$as_echo_n "checking for size_t... " >&6; }
-if test "${ac_cv_type_size_t+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_cv_type_size_t=no
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-if (sizeof (size_t))
-       return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-if (sizeof ((size_t)))
-         return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  :
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_type_size_t=yes
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5
-$as_echo "$ac_cv_type_size_t" >&6; }
-if test "x$ac_cv_type_size_t" = x""yes; then
-  :
-else
-
-cat >>confdefs.h <<_ACEOF
-#define size_t unsigned int
-_ACEOF
-
-fi
-
-{ $as_echo "$as_me:$LINENO: checking for mode_t" >&5
-$as_echo_n "checking for mode_t... " >&6; }
-if test "${ac_cv_type_mode_t+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_cv_type_mode_t=no
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-if (sizeof (mode_t))
-       return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
 {
-if (sizeof ((mode_t)))
-         return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
 case "(($ac_try" in
   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
   *) ac_try_echo=$ac_try;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
   ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
         test -z "$ac_c_werror_flag" ||
         test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  :
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_type_mode_t=yes
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then :
+  ac_retval=0
 else
   $as_echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_mode_t" >&5
-$as_echo "$ac_cv_type_mode_t" >&6; }
-if test "x$ac_cv_type_mode_t" = x""yes; then
-  :
-else
-
-cat >>confdefs.h <<_ACEOF
-#define mode_t int
-_ACEOF
-
+       ac_retval=1
 fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
 
+} # ac_fn_c_try_link
 
-  { $as_echo "$as_me:$LINENO: checking for int8_t" >&5
-$as_echo_n "checking for int8_t... " >&6; }
-if test "${ac_cv_c_int8_t+set}" = set; then
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval "test \"\${$3+set}\"" = set; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
   $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
 else
-  ac_cv_c_int8_t=no
-     for ac_type in 'int8_t' 'int' 'long int' \
-        'long long int' 'short int' 'signed char'; do
-       cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-static int test_array [1 - 2 * !(0 < ($ac_type) (((($ac_type) 1 << (8 - 2)) - 1) * 2 + 1))];
-test_array [0] = 0
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-static int test_array [1 - 2 * !(($ac_type) (((($ac_type) 1 << (8 - 2)) - 1) * 2 + 1)
-                < ($ac_type) (((($ac_type) 1 << (8 - 2)) - 1) * 2 + 2))];
-test_array [0] = 0
-
-  ;
-  return 0;
-}
+$4
+#include <$2>
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  :
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       case $ac_type in
-  int8_t) ac_cv_c_int8_t=yes ;;
-  *) ac_cv_c_int8_t=$ac_type ;;
-esac
-
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
+  ac_header_compiler=no
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-       test "$ac_cv_c_int8_t" != no && break
-     done
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_int8_t" >&5
-$as_echo "$ac_cv_c_int8_t" >&6; }
-  case $ac_cv_c_int8_t in #(
-  no|yes) ;; #(
-  *)
-
-cat >>confdefs.h <<_ACEOF
-#define int8_t $ac_cv_c_int8_t
-_ACEOF
-;;
-  esac
-
-
-  { $as_echo "$as_me:$LINENO: checking for int16_t" >&5
-$as_echo_n "checking for int16_t... " >&6; }
-if test "${ac_cv_c_int16_t+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_cv_c_int16_t=no
-     for ac_type in 'int16_t' 'int' 'long int' \
-        'long long int' 'short int' 'signed char'; do
-       cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-static int test_array [1 - 2 * !(0 < ($ac_type) (((($ac_type) 1 << (16 - 2)) - 1) * 2 + 1))];
-test_array [0] = 0
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
 
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-static int test_array [1 - 2 * !(($ac_type) (((($ac_type) 1 << (16 - 2)) - 1) * 2 + 1)
-                < ($ac_type) (((($ac_type) 1 << (16 - 2)) - 1) * 2 + 2))];
-test_array [0] = 0
-
-  ;
-  return 0;
-}
+#include <$2>
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  :
+if ac_fn_c_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       case $ac_type in
-  int16_t) ac_cv_c_int16_t=yes ;;
-  *) ac_cv_c_int16_t=$ac_type ;;
-esac
-
+  ac_header_preproc=no
 fi
+rm -f conftest.err conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
+  $as_echo_n "(cached) " >&6
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
+  eval "$3=\$ac_header_compiler"
 fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-       test "$ac_cv_c_int16_t" != no && break
-     done
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_int16_t" >&5
-$as_echo "$ac_cv_c_int16_t" >&6; }
-  case $ac_cv_c_int16_t in #(
-  no|yes) ;; #(
-  *)
-
-cat >>confdefs.h <<_ACEOF
-#define int16_t $ac_cv_c_int16_t
-_ACEOF
-;;
-  esac
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
 
+} # ac_fn_c_check_header_mongrel
 
-  { $as_echo "$as_me:$LINENO: checking for int32_t" >&5
-$as_echo_n "checking for int32_t... " >&6; }
-if test "${ac_cv_c_int32_t+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_cv_c_int32_t=no
-     for ac_type in 'int32_t' 'int' 'long int' \
-        'long long int' 'short int' 'signed char'; do
-       cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
 {
-static int test_array [1 - 2 * !(0 < ($ac_type) (((($ac_type) 1 << (32 - 2)) - 1) * 2 + 1))];
-test_array [0] = 0
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
 case "(($ac_try" in
   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
   *) ac_try_echo=$ac_try;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
   ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-static int test_array [1 - 2 * !(($ac_type) (((($ac_type) 1 << (32 - 2)) - 1) * 2 + 1)
-                < ($ac_type) (((($ac_type) 1 << (32 - 2)) - 1) * 2 + 2))];
-test_array [0] = 0
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
   *) ac_try_echo=$ac_try;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
   ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  :
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
 else
-  $as_echo "$as_me: failed program was:" >&5
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-       case $ac_type in
-  int32_t) ac_cv_c_int32_t=yes ;;
-  *) ac_cv_c_int32_t=$ac_type ;;
-esac
-
+       ac_retval=$ac_status
 fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
+} # ac_fn_c_try_run
 
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-       test "$ac_cv_c_int32_t" != no && break
-     done
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_int32_t" >&5
-$as_echo "$ac_cv_c_int32_t" >&6; }
-  case $ac_cv_c_int32_t in #(
-  no|yes) ;; #(
-  *)
-
-cat >>confdefs.h <<_ACEOF
-#define int32_t $ac_cv_c_int32_t
-_ACEOF
-;;
-  esac
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
 
+} # ac_fn_c_check_header_compile
 
-  { $as_echo "$as_me:$LINENO: checking for int64_t" >&5
-$as_echo_n "checking for int64_t... " >&6; }
-if test "${ac_cv_c_int64_t+set}" = set; then
+# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES
+# ----------------------------------------------------
+# Tries to find if the field MEMBER exists in type AGGR, after including
+# INCLUDES, setting cache variable VAR accordingly.
+ac_fn_c_check_member ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
+$as_echo_n "checking for $2.$3... " >&6; }
+if eval "test \"\${$4+set}\"" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  ac_cv_c_int64_t=no
-     for ac_type in 'int64_t' 'int' 'long int' \
-        'long long int' 'short int' 'signed char'; do
-       cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_includes_default
+$5
 int
 main ()
 {
-static int test_array [1 - 2 * !(0 < ($ac_type) (((($ac_type) 1 << (64 - 2)) - 1) * 2 + 1))];
-test_array [0] = 0
-
+static $2 ac_aggr;
+if (ac_aggr.$3)
+return 0;
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$4=yes"
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_includes_default
+$5
 int
 main ()
 {
-static int test_array [1 - 2 * !(($ac_type) (((($ac_type) 1 << (64 - 2)) - 1) * 2 + 1)
-                < ($ac_type) (((($ac_type) 1 << (64 - 2)) - 1) * 2 + 2))];
-test_array [0] = 0
-
+static $2 ac_aggr;
+if (sizeof ac_aggr.$3)
+return 0;
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  :
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$4=yes"
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       case $ac_type in
-  int64_t) ac_cv_c_int64_t=yes ;;
-  *) ac_cv_c_int64_t=$ac_type ;;
-esac
-
+  eval "$4=no"
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-       test "$ac_cv_c_int64_t" != no && break
-     done
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_int64_t" >&5
-$as_echo "$ac_cv_c_int64_t" >&6; }
-  case $ac_cv_c_int64_t in #(
-  no|yes) ;; #(
-  *)
+eval ac_res=\$$4
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
 
-cat >>confdefs.h <<_ACEOF
-#define int64_t $ac_cv_c_int64_t
-_ACEOF
-;;
-  esac
+} # ac_fn_c_check_member
 
-{ $as_echo "$as_me:$LINENO: checking for ssize_t" >&5
-$as_echo_n "checking for ssize_t... " >&6; }
-if test "${ac_cv_type_ssize_t+set}" = set; then
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  ac_cv_type_ssize_t=no
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  eval "$3=no"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_includes_default
+$4
 int
 main ()
 {
-if (sizeof (ssize_t))
-       return 0;
+if (sizeof ($2))
+        return 0;
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_includes_default
+$4
 int
 main ()
 {
-if (sizeof ((ssize_t)))
-         return 0;
+if (sizeof (($2)))
+           return 0;
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  :
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+if ac_fn_c_try_compile "$LINENO"; then :
 
-       ac_cv_type_ssize_t=yes
+else
+  eval "$3=yes"
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_ssize_t" >&5
-$as_echo "$ac_cv_type_ssize_t" >&6; }
-if test "x$ac_cv_type_ssize_t" = x""yes; then
-  :
-else
-
-cat >>confdefs.h <<_ACEOF
-#define ssize_t int
-_ACEOF
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
 
-fi
+} # ac_fn_c_check_type
 
-{ $as_echo "$as_me:$LINENO: checking for uid_t in sys/types.h" >&5
-$as_echo_n "checking for uid_t in sys/types.h... " >&6; }
-if test "${ac_cv_type_uid_t+set}" = set; then
+# ac_fn_c_find_intX_t LINENO BITS VAR
+# -----------------------------------
+# Finds a signed integer type with width BITS, setting cache variable VAR
+# accordingly.
+ac_fn_c_find_intX_t ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5
+$as_echo_n "checking for int$2_t... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  eval "$3=no"
+     # Order is important - never check a type that is potentially smaller
+     # than half of the expected target width.
+     for ac_type in int$2_t 'int' 'long int' \
+        'long long int' 'short int' 'signed char'; do
+       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-#include <sys/types.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  $EGREP "uid_t" >/dev/null 2>&1; then
-  ac_cv_type_uid_t=yes
-else
-  ac_cv_type_uid_t=no
-fi
-rm -f conftest*
-
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_uid_t" >&5
-$as_echo "$ac_cv_type_uid_t" >&6; }
-if test $ac_cv_type_uid_t = no; then
-
-cat >>confdefs.h <<\_ACEOF
-#define uid_t int
-_ACEOF
-
-
-cat >>confdefs.h <<\_ACEOF
-#define gid_t int
-_ACEOF
-
-fi
-
+$ac_includes_default
+            enum { N = $2 / 2 - 1 };
+int
+main ()
+{
+static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))];
+test_array [0] = 0
 
-  { $as_echo "$as_me:$LINENO: checking for uint8_t" >&5
-$as_echo_n "checking for uint8_t... " >&6; }
-if test "${ac_cv_c_uint8_t+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_cv_c_uint8_t=no
-     for ac_type in 'uint8_t' 'unsigned int' 'unsigned long int' \
-        'unsigned long long int' 'unsigned short int' 'unsigned char'; do
-       cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
+  ;
+  return 0;
+}
 _ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 $ac_includes_default
+               enum { N = $2 / 2 - 1 };
 int
 main ()
 {
-static int test_array [1 - 2 * !(($ac_type) -1 >> (8 - 1) == 1)];
+static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1)
+                < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))];
 test_array [0] = 0
 
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  case $ac_type in
-  uint8_t) ac_cv_c_uint8_t=yes ;;
-  *) ac_cv_c_uint8_t=$ac_type ;;
-esac
+if ac_fn_c_try_compile "$LINENO"; then :
 
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
+  case $ac_type in #(
+  int$2_t) :
+    eval "$3=yes" ;; #(
+  *) :
+    eval "$3=\$ac_type" ;;
+esac
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-       test "$ac_cv_c_uint8_t" != no && break
-     done
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_uint8_t" >&5
-$as_echo "$ac_cv_c_uint8_t" >&6; }
-  case $ac_cv_c_uint8_t in #(
-  no|yes) ;; #(
-  *)
-
-cat >>confdefs.h <<\_ACEOF
-#define _UINT8_T 1
-_ACEOF
-
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+       if eval test \"x\$"$3"\" = x"no"; then :
 
-cat >>confdefs.h <<_ACEOF
-#define uint8_t $ac_cv_c_uint8_t
-_ACEOF
-;;
-  esac
+else
+  break
+fi
+     done
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
 
+} # ac_fn_c_find_intX_t
 
-  { $as_echo "$as_me:$LINENO: checking for uint16_t" >&5
-$as_echo_n "checking for uint16_t... " >&6; }
-if test "${ac_cv_c_uint16_t+set}" = set; then
+# ac_fn_c_find_uintX_t LINENO BITS VAR
+# ------------------------------------
+# Finds an unsigned integer type with width BITS, setting cache variable VAR
+# accordingly.
+ac_fn_c_find_uintX_t ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5
+$as_echo_n "checking for uint$2_t... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  ac_cv_c_uint16_t=no
-     for ac_type in 'uint16_t' 'unsigned int' 'unsigned long int' \
+  eval "$3=no"
+     # Order is important - never check a type that is potentially smaller
+     # than half of the expected target width.
+     for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \
         'unsigned long long int' 'unsigned short int' 'unsigned char'; do
-       cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 $ac_includes_default
 int
 main ()
 {
-static int test_array [1 - 2 * !(($ac_type) -1 >> (16 - 1) == 1)];
+static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)];
 test_array [0] = 0
 
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  case $ac_type in
-  uint16_t) ac_cv_c_uint16_t=yes ;;
-  *) ac_cv_c_uint16_t=$ac_type ;;
+if ac_fn_c_try_compile "$LINENO"; then :
+  case $ac_type in #(
+  uint$2_t) :
+    eval "$3=yes" ;; #(
+  *) :
+    eval "$3=\$ac_type" ;;
 esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+       if eval test \"x\$"$3"\" = x"no"; then :
 
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
+  break
 fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-       test "$ac_cv_c_uint16_t" != no && break
      done
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_uint16_t" >&5
-$as_echo "$ac_cv_c_uint16_t" >&6; }
-  case $ac_cv_c_uint16_t in #(
-  no|yes) ;; #(
-  *)
-
-
-cat >>confdefs.h <<_ACEOF
-#define uint16_t $ac_cv_c_uint16_t
-_ACEOF
-;;
-  esac
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
 
+} # ac_fn_c_find_uintX_t
 
-  { $as_echo "$as_me:$LINENO: checking for uint32_t" >&5
-$as_echo_n "checking for uint32_t... " >&6; }
-if test "${ac_cv_c_uint32_t+set}" = set; then
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  ac_cv_c_uint32_t=no
-     for ac_type in 'uint32_t' 'unsigned int' 'unsigned long int' \
-        'unsigned long long int' 'unsigned short int' 'unsigned char'; do
-       cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_includes_default
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
 int
 main ()
 {
-static int test_array [1 - 2 * !(($ac_type) -1 >> (32 - 1) == 1)];
-test_array [0] = 0
-
+return $2 ();
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  case $ac_type in
-  uint32_t) ac_cv_c_uint32_t=yes ;;
-  *) ac_cv_c_uint32_t=$ac_type ;;
-esac
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_func
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.66.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
 
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
 
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
 
-fi
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-       test "$ac_cv_c_uint32_t" != no && break
-     done
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_uint32_t" >&5
-$as_echo "$ac_cv_c_uint32_t" >&6; }
-  case $ac_cv_c_uint32_t in #(
-  no|yes) ;; #(
-  *)
+_ASUNAME
 
-cat >>confdefs.h <<\_ACEOF
-#define _UINT32_T 1
-_ACEOF
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
 
+} >&5
 
-cat >>confdefs.h <<_ACEOF
-#define uint32_t $ac_cv_c_uint32_t
-_ACEOF
-;;
-  esac
+cat >&5 <<_ACEOF
 
 
-  { $as_echo "$as_me:$LINENO: checking for uint64_t" >&5
-$as_echo_n "checking for uint64_t... " >&6; }
-if test "${ac_cv_c_uint64_t+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_cv_c_uint64_t=no
-     for ac_type in 'uint64_t' 'unsigned int' 'unsigned long int' \
-        'unsigned long long int' 'unsigned short int' 'unsigned char'; do
-       cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-static int test_array [1 - 2 * !(($ac_type) -1 >> (64 - 1) == 1)];
-test_array [0] = 0
+## ----------- ##
+## Core tests. ##
+## ----------- ##
 
-  ;
-  return 0;
-}
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  case $ac_type in
-  uint64_t) ac_cv_c_uint64_t=yes ;;
-  *) ac_cv_c_uint64_t=$ac_type ;;
-esac
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
 
 
-fi
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+       ac_must_keep_next=false # Got value, back to normal.
+      else
+       case $ac_arg in
+         *=* | --config-cache | -C | -disable-* | --disable-* \
+         | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+         | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+         | -with-* | --with-* | -without-* | --without-* | --x)
+           case "$ac_configure_args0 " in
+             "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+           esac
+           ;;
+         -* ) ac_must_keep_next=true ;;
+       esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-       test "$ac_cv_c_uint64_t" != no && break
-     done
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_uint64_t" >&5
-$as_echo "$ac_cv_c_uint64_t" >&6; }
-  case $ac_cv_c_uint64_t in #(
-  no|yes) ;; #(
-  *)
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
 
-cat >>confdefs.h <<\_ACEOF
-#define _UINT64_T 1
-_ACEOF
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+       "s/'\''/'\''\\\\'\'''\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
 
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
 
-cat >>confdefs.h <<_ACEOF
-#define uint64_t $ac_cv_c_uint64_t
-_ACEOF
-;;
-  esac
+    if test -n "$ac_subst_files"; then
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      echo
+      for ac_var in $ac_subst_files
+      do
+       eval ac_val=\$$ac_var
+       case $ac_val in
+       *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+       esac
+       $as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
 
-{ $as_echo "$as_me:$LINENO: checking for struct stat.st_rdev" >&5
-$as_echo_n "checking for struct stat.st_rdev... " >&6; }
-if test "${ac_cv_member_struct_stat_st_rdev+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-static struct stat ac_aggr;
-if (ac_aggr.st_rdev)
-return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_member_struct_stat_st_rdev=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+    if test -s confdefs.h; then
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
 
-       cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-static struct stat ac_aggr;
-if (sizeof ac_aggr.st_rdev)
-return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_member_struct_stat_st_rdev=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
 
-       ac_cv_member_struct_stat_st_rdev=no
-fi
+$as_echo "/* confdefs.h */" > confdefs.h
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
+# Predefined preprocessor variables.
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_rdev" >&5
-$as_echo "$ac_cv_member_struct_stat_st_rdev" >&6; }
-if test "x$ac_cv_member_struct_stat_st_rdev" = x""yes; then
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
 
 cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_STAT_ST_RDEV 1
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
 _ACEOF
 
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
 
-fi
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
 
-{ $as_echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5
-$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; }
-if test "${ac_cv_struct_tm+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
 _ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <sys/types.h>
-#include <time.h>
 
-int
-main ()
-{
-struct tm tm;
-                                    int *p = &tm.tm_sec;
-                                    return !p;
-  ;
-  return 0;
-}
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_struct_tm=time.h
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
 
-       ac_cv_struct_tm=sys/time.h
-fi
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_struct_tm" >&5
-$as_echo "$ac_cv_struct_tm" >&6; }
-if test $ac_cv_struct_tm = sys/time.h; then
-
-cat >>confdefs.h <<\_ACEOF
-#define TM_IN_SYS_TIME 1
-_ACEOF
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
+done
 
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
 fi
 
+as_fn_append ac_header_list " stdlib.h"
+as_fn_append ac_header_list " unistd.h"
+as_fn_append ac_header_list " sys/param.h"
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+       # differences in whitespace do not lead to failure.
+       ac_old_val_w=`echo x $ac_old_val`
+       ac_new_val_w=`echo x $ac_new_val`
+       if test "$ac_old_val_w" != "$ac_new_val_w"; then
+         { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+         ac_cache_corrupted=:
+       else
+         { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+         eval $ac_var=\$ac_old_val
+       fi
+       { $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+       { $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
 
-################################################################################
-
-
-
-
-
-
-
-
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 
 
+ac_config_headers="$ac_config_headers lib/misc/configure.h"
 
 
+################################################################################
+ac_aux_dir=
+for ac_dir in autoconf "$srcdir"/autoconf; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  as_fn_error $? "cannot find install-sh, install.sh, or shtool in autoconf \"$srcdir\"/autoconf" "$LINENO" 5
+fi
 
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
 
 
 
+################################################################################
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if test "${ac_cv_build+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
 
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if test "${ac_cv_host+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
 
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
 
 
-for ac_func in ftruncate gethostname getpagesize \
-  gettimeofday memset mkdir mkfifo rmdir munmap nl_langinfo setenv setlocale \
-  strcasecmp strchr strcspn strspn strdup strncasecmp strerror strrchr \
-  strstr strtol strtoul uname
-do
-as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
-$as_echo_n "checking for $ac_func... " >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5
+$as_echo_n "checking target system type... " >&6; }
+if test "${ac_cv_target+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
+  if test "x$target_alias" = x; then
+  ac_cv_target=$ac_cv_host
+else
+  ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5
+fi
 
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5
+$as_echo "$ac_cv_target" >&6; }
+case $ac_cv_target in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;;
+esac
+target=$ac_cv_target
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_target
+shift
+target_cpu=$1
+target_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+target_os=$*
+IFS=$ac_save_IFS
+case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac
 
-#undef $ac_func
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $ac_func ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub_$ac_func || defined __stub___$ac_func
-choke me
-#endif
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+  test "$program_prefix$program_suffix$program_transform_name" = \
+    NONENONEs,x,x, &&
+  program_prefix=${target_alias}-
 
-int
-main ()
-{
-return $ac_func ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
+case "$host_os" in
+       linux*)
+               CFLAGS="$CFLAGS"
+               COPTIMISE_FLAG="-O2"
+               CLDFLAGS="$CLDFLAGS -Wl,--version-script,.export.sym"
+               ELDFLAGS="-Wl,--export-dynamic"
+               # FIXME Generate list and use --dynamic-list=.dlopen.sym
+               CLDWHOLEARCHIVE="-Wl,-whole-archive"
+               CLDNOWHOLEARCHIVE="-Wl,-no-whole-archive"
+               LDDEPS="$LDDEPS .export.sym"
+               LIB_SUFFIX=so
+               DEVMAPPER=yes
+               LVMETAD=no
+               ODIRECT=yes
+               DM_IOCTLS=yes
+               SELINUX=yes
+               CLUSTER=internal
+               FSADM=yes
+               BLKDEACTIVATE=yes
+               ;;
+       darwin*)
+               CFLAGS="$CFLAGS -no-cpp-precomp -fno-common"
+               COPTIMISE_FLAG="-O2"
+               CLDFLAGS="$CLDFLAGS"
+               ELDFLAGS=
+               CLDWHOLEARCHIVE="-all_load"
+               CLDNOWHOLEARCHIVE=
+               LIB_SUFFIX=dylib
+               DEVMAPPER=yes
+               ODIRECT=no
+               DM_IOCTLS=no
+               SELINUX=no
+               CLUSTER=none
+               FSADM=no
+               BLKDEACTIVATE=no
+               ;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  eval "$as_ac_var=yes"
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       eval "$as_ac_var=no"
-fi
 
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-fi
-ac_res=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-as_val=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if test "${ac_cv_path_SED+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+            ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+     for ac_i in 1 2 3 4 5 6 7; do
+       ac_script="$ac_script$as_nl$ac_script"
+     done
+     echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+     { ac_script=; unset ac_script;}
+     if test -z "$SED"; then
+  ac_path_SED_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue
+# Check for GNU ac_path_SED and select it if it is found.
+  # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+  ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo '' >> "conftest.nl"
+    "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_SED_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_SED="$ac_path_SED"
+      ac_path_SED_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
 
+      $ac_path_SED_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_SED"; then
+    as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+  fi
 else
-  { { $as_echo "$as_me:$LINENO: error: bailing out" >&5
-$as_echo "$as_me: error: bailing out" >&2;}
-   { (exit 1); exit 1; }; }
+  ac_cv_path_SED=$SED
 fi
-done
 
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+  rm -f conftest.sed
 
-for ac_func in siginterrupt
+for ac_prog in gawk mawk nawk awk
 do
-as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
-$as_echo_n "checking for $ac_func... " >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_AWK+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef $ac_func
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $ac_func ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub_$ac_func || defined __stub___$ac_func
-choke me
-#endif
-
-int
-main ()
-{
-return $ac_func ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  eval "$as_ac_var=yes"
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_AWK="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
-       eval "$as_ac_var=no"
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
 fi
-ac_res=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-as_val=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
-
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
+
+
+  test -n "$AWK" && break
 done
 
-# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
-# for constant arguments.  Useless!
-{ $as_echo "$as_me:$LINENO: checking for working alloca.h" >&5
-$as_echo_n "checking for working alloca.h... " >&6; }
-if test "${ac_cv_working_alloca_h+set}" = set; then
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <alloca.h>
-int
-main ()
-{
-char *p = (char *) alloca (2 * sizeof (int));
-                         if (p) return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_working_alloca_h=yes
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
-       ac_cv_working_alloca_h=no
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_working_alloca_h" >&5
-$as_echo "$ac_cv_working_alloca_h" >&6; }
-if test $ac_cv_working_alloca_h = yes; then
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
 
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_ALLOCA_H 1
-_ACEOF
 
 fi
-
-{ $as_echo "$as_me:$LINENO: checking for alloca" >&5
-$as_echo_n "checking for alloca... " >&6; }
-if test "${ac_cv_func_alloca_works+set}" = set; then
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#ifdef __GNUC__
-# define alloca __builtin_alloca
-#else
-# ifdef _MSC_VER
-#  include <malloc.h>
-#  define alloca _alloca
-# else
-#  ifdef HAVE_ALLOCA_H
-#   include <alloca.h>
-#  else
-#   ifdef _AIX
- #pragma alloca
-#   else
-#    ifndef alloca /* predefined by HP cc +Olibcalls */
-char *alloca ();
-#    endif
-#   endif
-#  endif
-# endif
-#endif
-
-int
-main ()
-{
-char *p = (char *) alloca (1);
-                                   if (p) return 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_func_alloca_works=yes
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
-       ac_cv_func_alloca_works=no
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_alloca_works" >&5
-$as_echo "$ac_cv_func_alloca_works" >&6; }
-
-if test $ac_cv_func_alloca_works = yes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_ALLOCA 1
-_ACEOF
-
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
 else
-  # The SVR3 libPW and SVR4 libucb both contain incompatible functions
-# that cause trouble.  Some versions do not even contain alloca or
-# contain a buggy version.  If you still want to use their alloca,
-# use ar to extract alloca.o from them instead of compiling alloca.c.
-
-ALLOCA=\${LIBOBJDIR}alloca.$ac_objext
-
-cat >>confdefs.h <<\_ACEOF
-#define C_ALLOCA 1
-_ACEOF
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
 
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
 
-{ $as_echo "$as_me:$LINENO: checking whether \`alloca.c' needs Cray hooks" >&5
-$as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; }
-if test "${ac_cv_os_cray+set}" = set; then
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#if defined CRAY && ! defined CRAY2
-webecray
-#else
-wenotbecray
-#endif
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  $EGREP "webecray" >/dev/null 2>&1; then
-  ac_cv_os_cray=yes
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
 else
-  ac_cv_os_cray=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
-rm -f conftest*
 
+
+  fi
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_os_cray" >&5
-$as_echo "$ac_cv_os_cray" >&6; }
-if test $ac_cv_os_cray = yes; then
-  for ac_func in _getb67 GETB67 getb67; do
-    as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
-$as_echo_n "checking for $ac_func... " >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
-#undef $ac_func
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $ac_func ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub_$ac_func || defined __stub___$ac_func
-choke me
-#endif
 
-int
-main ()
-{
-return $ac_func ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  eval "$as_ac_var=yes"
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
-       eval "$as_ac_var=no"
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
 fi
-ac_res=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-as_val=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-
-cat >>confdefs.h <<_ACEOF
-#define CRAY_STACKSEG_END $ac_func
-_ACEOF
-
-    break
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
+
+    test -n "$CC" && break
   done
 fi
-
-{ $as_echo "$as_me:$LINENO: checking stack direction for C alloca" >&5
-$as_echo_n "checking stack direction for C alloca... " >&6; }
-if test "${ac_cv_c_stack_direction+set}" = set; then
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  if test "$cross_compiling" = yes; then
-  ac_cv_c_stack_direction=0
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-find_stack_direction ()
-{
-  static char *addr = 0;
-  auto char dummy;
-  if (addr == 0)
-    {
-      addr = &dummy;
-      return find_stack_direction ();
-    }
-  else
-    return (&dummy > addr) ? 1 : -1;
-}
-
-int
-main ()
-{
-  return find_stack_direction () < 0;
-}
-_ACEOF
-rm -f conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_cv_c_stack_direction=1
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
 else
-  $as_echo "$as_me: program exited with status $ac_status" >&5
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
-( exit $ac_status )
-ac_cv_c_stack_direction=-1
 fi
-rm -rf conftest.dSYM
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
 fi
-
-
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_stack_direction" >&5
-$as_echo "$ac_cv_c_stack_direction" >&6; }
 
-cat >>confdefs.h <<_ACEOF
-#define STACK_DIRECTION $ac_cv_c_stack_direction
-_ACEOF
 
+  test -n "$ac_ct_CC" && break
+done
 
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
 fi
 
-{ $as_echo "$as_me:$LINENO: checking whether closedir returns void" >&5
-$as_echo_n "checking whether closedir returns void... " >&6; }
-if test "${ac_cv_func_closedir_void+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  if test "$cross_compiling" = yes; then
-  ac_cv_func_closedir_void=yes
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header_dirent>
-#ifndef __cplusplus
-int closedir ();
-#endif
+fi
 
-int
-main ()
-{
-return closedir (opendir (".")) != 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest$ac_exeext
-if { (ac_try="$ac_link"
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
 case "(($ac_try" in
   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
   *) ac_try_echo=$ac_try;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_try") 2>&5
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_cv_func_closedir_void=no
-else
-  $as_echo "$as_me: program exited with status $ac_status" >&5
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-( exit $ac_status )
-ac_cv_func_closedir_void=yes
-fi
-rm -rf conftest.dSYM
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
-fi
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
 
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
 
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_closedir_void" >&5
-$as_echo "$ac_cv_func_closedir_void" >&6; }
-if test $ac_cv_func_closedir_void = yes; then
+int
+main ()
+{
 
-cat >>confdefs.h <<\_ACEOF
-#define CLOSEDIR_VOID 1
+  ;
+  return 0;
+}
 _ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
 
-fi
-
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
 
-for ac_header in unistd.h
+ac_rmfiles=
+for ac_file in $ac_files
 do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
 case "(($ac_try" in
   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
   *) ac_try_echo=$ac_try;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
   ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+       ;;
+    [ab].out )
+       # We found the default executable, but exeext='' is most
+       # certainly right.
+       break;;
+    *.* )
+       if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+       then :; else
+          ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+       fi
+       # We set ac_cv_exeext here because the later test for it is not
+       # safe: cross compilers may not add the suffix if given an `-o'
+       # argument, so we may need to know it at that point already.
+       # Even if this section looks crufty: it has the advantage of
+       # actually working.
+       break;;
+    * )
+       break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
 else
-  $as_echo "$as_me: failed program was:" >&5
+  ac_file=''
+fi
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-       ac_header_compiler=no
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
 case "(($ac_try" in
   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
   *) ac_try_echo=$ac_try;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
   ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  ac_header_preproc=no
-fi
-
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
-
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+         break;;
+    * ) break;;
+  esac
+done
 else
-  eval "$as_ac_Header=\$ac_header_preproc"
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-
-fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
 fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
 
-done
-
-{ $as_echo "$as_me:$LINENO: checking for working chown" >&5
-$as_echo_n "checking for working chown... " >&6; }
-if test "${ac_cv_func_chown_works+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  if test "$cross_compiling" = yes; then
-  ac_cv_func_chown_works=no
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_includes_default
-#include <fcntl.h>
-
+#include <stdio.h>
 int
 main ()
 {
-  char *f = "conftest.chown";
-  struct stat before, after;
-
-  if (creat (f, 0600) < 0)
-    return 1;
-  if (stat (f, &before) < 0)
-    return 1;
-  if (chown (f, (uid_t) -1, (gid_t) -1) == -1)
-    return 1;
-  if (stat (f, &after) < 0)
-    return 1;
-  return ! (before.st_uid == after.st_uid && before.st_gid == after.st_gid);
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
 
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest$ac_exeext
-if { (ac_try="$ac_link"
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
 case "(($ac_try" in
   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
   *) ac_try_echo=$ac_try;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
   (eval "$ac_link") 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
-  { (case "(($ac_try" in
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
   *) ac_try_echo=$ac_try;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
   (eval "$ac_try") 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_cv_func_chown_works=yes
-else
-  $as_echo "$as_me: program exited with status $ac_status" >&5
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-( exit $ac_status )
-ac_cv_func_chown_works=no
-fi
-rm -rf conftest.dSYM
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
-fi
-
-
-rm -f conftest.chown
-
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_chown_works" >&5
-$as_echo "$ac_cv_func_chown_works" >&6; }
-if test $ac_cv_func_chown_works = yes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_CHOWN 1
-_ACEOF
-
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+       cross_compiling=yes
+    else
+       { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+    fi
+  fi
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
 
-
-for ac_header in vfork.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if test "${ac_cv_objext+set}" = set; then :
   $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_header_compiler=no
-fi
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
+int
+main ()
+{
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
+  ;
+  return 0;
+}
 _ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
 case "(($ac_try" in
   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
   *) ac_try_echo=$ac_try;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
   ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
 else
   $as_echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-  ac_header_preproc=no
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
 fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
 else
-  eval "$as_ac_Header=\$ac_header_preproc"
+  ac_compiler_gnu=no
 fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
 
 fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
 fi
-
-done
-
-
-
-for ac_func in fork vfork
-do
-as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
-$as_echo_n "checking for $ac_func... " >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef $ac_func
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $ac_func ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub_$ac_func || defined __stub___$ac_func
-choke me
-#endif
 
 int
 main ()
 {
-return $ac_func ();
+
   ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  eval "$as_ac_var=yes"
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
 
-       eval "$as_ac_var=no"
-fi
+int
+main ()
+{
 
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-fi
-ac_res=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-as_val=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+  ;
+  return 0;
+}
 _ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
 
-fi
-done
-
-if test "x$ac_cv_func_fork" = xyes; then
-  { $as_echo "$as_me:$LINENO: checking for working fork" >&5
-$as_echo_n "checking for working fork... " >&6; }
-if test "${ac_cv_func_fork_works+set}" = set; then
-  $as_echo_n "(cached) " >&6
 else
-  if test "$cross_compiling" = yes; then
-  ac_cv_func_fork_works=cross
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  ac_c_werror_flag=$ac_save_c_werror_flag
+        CFLAGS="-g"
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_includes_default
+
 int
 main ()
 {
 
-         /* By Ruediger Kuhlmann. */
-         return fork () < 0;
-
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_cv_func_fork_works=yes
-else
-  $as_echo "$as_me: program exited with status $ac_status" >&5
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-( exit $ac_status )
-ac_cv_func_fork_works=no
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
 fi
-rm -rf conftest.dSYM
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-
-
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_fork_works" >&5
-$as_echo "$ac_cv_func_fork_works" >&6; }
-
-else
-  ac_cv_func_fork_works=$ac_cv_func_fork
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
 fi
-if test "x$ac_cv_func_fork_works" = xcross; then
-  case $host in
-    *-*-amigaos* | *-*-msdosdjgpp*)
-      # Override, as these systems have only a dummy fork() stub
-      ac_cv_func_fork_works=no
-      ;;
-    *)
-      ac_cv_func_fork_works=yes
-      ;;
-  esac
-  { $as_echo "$as_me:$LINENO: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5
-$as_echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
 fi
-ac_cv_func_vfork_works=$ac_cv_func_vfork
-if test "x$ac_cv_func_vfork" = xyes; then
-  { $as_echo "$as_me:$LINENO: checking for working vfork" >&5
-$as_echo_n "checking for working vfork... " >&6; }
-if test "${ac_cv_func_vfork_works+set}" = set; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  if test "$cross_compiling" = yes; then
-  ac_cv_func_vfork_works=cross
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-/* Thanks to Paul Eggert for this test.  */
-$ac_includes_default
-#include <sys/wait.h>
-#ifdef HAVE_VFORK_H
-# include <vfork.h>
-#endif
-/* On some sparc systems, changes by the child to local and incoming
-   argument registers are propagated back to the parent.  The compiler
-   is told about this with #include <vfork.h>, but some compilers
-   (e.g. gcc -O) don't grok <vfork.h>.  Test for this by using a
-   static variable whose address is put into a register that is
-   clobbered by the vfork.  */
-static void
-#ifdef __cplusplus
-sparc_address_test (int arg)
-# else
-sparc_address_test (arg) int arg;
-#endif
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
 {
-  static pid_t child;
-  if (!child) {
-    child = vfork ();
-    if (child < 0) {
-      perror ("vfork");
-      _exit(2);
-    }
-    if (!child) {
-      arg = getpid();
-      write(-1, "", 0);
-      _exit (arg);
-    }
-  }
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
 }
 
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
 int
 main ()
 {
-  pid_t parent = getpid ();
-  pid_t child;
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+       -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
 
-  sparc_address_test (0);
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
 
-  child = vfork ();
+fi
 
-  if (child == 0) {
-    /* Here is another test for sparc vfork register problems.  This
-       test uses lots of local variables, at least as many local
-       variables as main has allocated so far including compiler
-       temporaries.  4 locals are enough for gcc 1.40.3 on a Solaris
-       4.1.3 sparc, but we use 8 to be safe.  A buggy compiler should
-       reuse the register of parent for one of the local variables,
-       since it will think that parent can't possibly be used any more
-       in this routine.  Assigning to the local variable will thus
-       munge parent in the parent process.  */
-    pid_t
-      p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(),
-      p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid();
-    /* Convince the compiler that p..p7 are live; otherwise, it might
-       use the same hardware register for all 8 local variables.  */
-    if (p != p1 || p != p2 || p != p3 || p != p4
-       || p != p5 || p != p6 || p != p7)
-      _exit(1);
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
-    /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent
-       from child file descriptors.  If the child closes a descriptor
-       before it execs or exits, this munges the parent's descriptor
-       as well.  Test for this by closing stdout in the child.  */
-    _exit(close(fileno(stdout)) != 0);
-  } else {
-    int status;
-    struct stat st;
 
-    while (wait(&status) != child)
-      ;
-    return (
-        /* Was there some problem with vforking?  */
-        child < 0
 
-        /* Did the child fail?  (This shouldn't happen.)  */
-        || status
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if test "${ac_cv_prog_CPP+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
 
-        /* Did the vfork/compiler bug occur?  */
-        || parent != getpid()
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
 
-        /* Did the file descriptor bug occur?  */
-        || fstat(fileno(stdout), &st) != 0
-        );
-  }
-}
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
 _ACEOF
-rm -f conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_cv_func_vfork_works=yes
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
 else
-  $as_echo "$as_me: program exited with status $ac_status" >&5
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-( exit $ac_status )
-ac_cv_func_vfork_works=no
+  # Passes both tests.
+ac_preproc_ok=:
+break
 fi
-rm -rf conftest.dSYM
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
 fi
 
+    done
+    ac_cv_prog_CPP=$CPP
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_vfork_works" >&5
-$as_echo "$ac_cv_func_vfork_works" >&6; }
-
-fi;
-if test "x$ac_cv_func_fork_works" = xcross; then
-  ac_cv_func_vfork_works=$ac_cv_func_vfork
-  { $as_echo "$as_me:$LINENO: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5
-$as_echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;}
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
 fi
-
-if test "x$ac_cv_func_vfork_works" = xyes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_WORKING_VFORK 1
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
 _ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
 
 else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
 
-cat >>confdefs.h <<\_ACEOF
-#define vfork fork
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
 _ACEOF
-
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
 fi
-if test "x$ac_cv_func_fork_works" = xyes; then
+rm -f conftest.err conftest.$ac_ext
 
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_WORKING_FORK 1
-_ACEOF
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
 
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
 fi
 
-{ $as_echo "$as_me:$LINENO: checking whether lstat dereferences a symlink specified with a trailing slash" >&5
-$as_echo_n "checking whether lstat dereferences a symlink specified with a trailing slash... " >&6; }
-if test "${ac_cv_func_lstat_dereferences_slashed_symlink+set}" = set; then
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  rm -f conftest.sym conftest.file
-echo >conftest.file
-if test "$as_ln_s" = "ln -s" && ln -s conftest.file conftest.sym; then
-  if test "$cross_compiling" = yes; then
-  ac_cv_func_lstat_dereferences_slashed_symlink=no
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-struct stat sbuf;
-     /* Linux will dereference the symlink and fail.
-       That is better in the sense that it means we will not
-       have to compile and use the lstat wrapper.  */
-     return lstat ("conftest.sym/", &sbuf) == 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_cv_func_lstat_dereferences_slashed_symlink=yes
-else
-  $as_echo "$as_me: program exited with status $ac_status" >&5
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
 
-( exit $ac_status )
-ac_cv_func_lstat_dereferences_slashed_symlink=no
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
 fi
-rm -rf conftest.dSYM
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then :
+  $as_echo_n "(cached) " >&6
 else
-  # If the `ln -s' command failed, then we probably don't even
-  # have an lstat function.
-  ac_cv_func_lstat_dereferences_slashed_symlink=no
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
 fi
-rm -f conftest.sym conftest.file
 
+   fi
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_lstat_dereferences_slashed_symlink" >&5
-$as_echo "$ac_cv_func_lstat_dereferences_slashed_symlink" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
 
-test $ac_cv_func_lstat_dereferences_slashed_symlink = yes &&
 
-cat >>confdefs.h <<_ACEOF
-#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1
+if test $ac_cv_c_compiler_gnu = yes; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC needs -traditional" >&5
+$as_echo_n "checking whether $CC needs -traditional... " >&6; }
+if test "${ac_cv_prog_gcc_traditional+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+    ac_pattern="Autoconf.*'x'"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sgtty.h>
+Autoconf TIOCGETP
 _ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "$ac_pattern" >/dev/null 2>&1; then :
+  ac_cv_prog_gcc_traditional=yes
+else
+  ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
 
 
-if test $ac_cv_func_lstat_dereferences_slashed_symlink = no; then
-  case " $LIBOBJS " in
-  *" lstat.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS lstat.$ac_objext"
- ;;
-esac
+  if test $ac_cv_prog_gcc_traditional = no; then
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <termio.h>
+Autoconf TCGETA
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "$ac_pattern" >/dev/null 2>&1; then :
+  ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
 
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gcc_traditional" >&5
+$as_echo "$ac_cv_prog_gcc_traditional" >&6; }
+  if test $ac_cv_prog_gcc_traditional = yes; then
+    CC="$CC -traditional"
+  fi
 fi
 
-{ $as_echo "$as_me:$LINENO: checking whether lstat accepts an empty string" >&5
-$as_echo_n "checking whether lstat accepts an empty string... " >&6; }
-if test "${ac_cv_func_lstat_empty_string_bug+set}" = set; then
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  if test "$cross_compiling" = yes; then
-  ac_cv_func_lstat_empty_string_bug=yes
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-struct stat sbuf;
-  return lstat ("", &sbuf) == 0;
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+  ./ | .// | /[cC]/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+       if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+         if test $ac_prog = install &&
+           grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # AIX install.  It has an incompatible calling convention.
+           :
+         elif test $ac_prog = install &&
+           grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # program-specific install script used by HP pwplus--don't use.
+           :
+         else
+           rm -rf conftest.one conftest.two conftest.dir
+           echo one > conftest.one
+           echo two > conftest.two
+           mkdir conftest.dir
+           if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+             test -s conftest.one && test -s conftest.two &&
+             test -s conftest.dir/conftest.one &&
+             test -s conftest.dir/conftest.two
+           then
+             ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+             break 3
+           fi
+         fi
+       fi
+      done
+    done
+    ;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_cv_func_lstat_empty_string_bug=no
-else
-  $as_echo "$as_me: program exited with status $ac_status" >&5
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
 
-( exit $ac_status )
-ac_cv_func_lstat_empty_string_bug=yes
-fi
-rm -rf conftest.dSYM
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
-fi
+  done
+IFS=$as_save_IFS
 
+rm -rf conftest.one conftest.two conftest.dir
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_lstat_empty_string_bug" >&5
-$as_echo "$ac_cv_func_lstat_empty_string_bug" >&6; }
-if test $ac_cv_func_lstat_empty_string_bug = yes; then
-  case " $LIBOBJS " in
-  *" lstat.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS lstat.$ac_objext"
- ;;
-esac
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
 
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
 
-cat >>confdefs.h <<_ACEOF
-#define HAVE_LSTAT_EMPTY_STRING_BUG 1
-_ACEOF
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
 
-fi
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
 
-for ac_header in stdlib.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\"" = set; then :
   $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+       @echo '@@@%%%=$(MAKE)=@@@%%%'
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_header_compiler=no
+rm -f conftest.make
 fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  SET_MAKE=
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  ac_header_preproc=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
 fi
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
-
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+  if test "${ac_cv_path_mkdir+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  eval "$as_ac_Header=\$ac_header_preproc"
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in mkdir gmkdir; do
+        for ac_exec_ext in '' $ac_executable_extensions; do
+          { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
+          case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+            'mkdir (GNU coreutils) '* | \
+            'mkdir (coreutils) '* | \
+            'mkdir (fileutils) '4.1*)
+              ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+              break 3;;
+          esac
+        done
+       done
+  done
+IFS=$as_save_IFS
 
 fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
 
+  test -d ./--version && rmdir ./--version
+  if test "${ac_cv_path_mkdir+set}" = set; then
+    MKDIR_P="$ac_cv_path_mkdir -p"
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for MKDIR_P within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    MKDIR_P="$ac_install_sh -d"
+  fi
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
 
-done
-
-{ $as_echo "$as_me:$LINENO: checking for GNU libc compatible malloc" >&5
-$as_echo_n "checking for GNU libc compatible malloc... " >&6; }
-if test "${ac_cv_func_malloc_0_nonnull+set}" = set; then
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_RANLIB+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  if test "$cross_compiling" = yes; then
-  ac_cv_func_malloc_0_nonnull=no
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#if defined STDC_HEADERS || defined HAVE_STDLIB_H
-# include <stdlib.h>
-#else
-char *malloc ();
-#endif
-
-int
-main ()
-{
-return ! malloc (0);
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_cv_func_malloc_0_nonnull=yes
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
 else
-  $as_echo "$as_me: program exited with status $ac_status" >&5
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
-( exit $ac_status )
-ac_cv_func_malloc_0_nonnull=no
 fi
-rm -rf conftest.dSYM
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
 fi
-
-
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_malloc_0_nonnull" >&5
-$as_echo "$ac_cv_func_malloc_0_nonnull" >&6; }
-if test $ac_cv_func_malloc_0_nonnull = yes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_MALLOC 1
-_ACEOF
-
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
 else
-  cat >>confdefs.h <<\_ACEOF
-#define HAVE_MALLOC 0
-_ACEOF
-
-   case " $LIBOBJS " in
-  *" malloc.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS malloc.$ac_objext"
- ;;
-esac
-
-
-cat >>confdefs.h <<\_ACEOF
-#define malloc rpl_malloc
-_ACEOF
-
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
 
-
-{ $as_echo "$as_me:$LINENO: checking for working memcmp" >&5
-$as_echo_n "checking for working memcmp... " >&6; }
-if test "${ac_cv_func_memcmp_working+set}" = set; then
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  if test "$cross_compiling" = yes; then
-  ac_cv_func_memcmp_working=no
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-
-  /* Some versions of memcmp are not 8-bit clean.  */
-  char c0 = '\100', c1 = '\200', c2 = '\201';
-  if (memcmp(&c0, &c2, 1) >= 0 || memcmp(&c1, &c2, 1) >= 0)
-    return 1;
-
-  /* The Next x86 OpenStep bug shows up only when comparing 16 bytes
-     or more and with at least one buffer not starting on a 4-byte boundary.
-     William Lewis provided this test program.   */
-  {
-    char foo[21];
-    char bar[21];
-    int i;
-    for (i = 0; i < 4; i++)
-      {
-       char *a = foo + i;
-       char *b = bar + i;
-       strcpy (a, "--------01111111");
-       strcpy (b, "--------10000000");
-       if (memcmp (a, b, 16) >= 0)
-         return 1;
-      }
-    return 0;
-  }
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_cv_func_memcmp_working=yes
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
 else
-  $as_echo "$as_me: program exited with status $ac_status" >&5
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_RANLIB="ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
-( exit $ac_status )
-ac_cv_func_memcmp_working=no
 fi
-rm -rf conftest.dSYM
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
 fi
-
-
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_memcmp_working" >&5
-$as_echo "$ac_cv_func_memcmp_working" >&6; }
-test $ac_cv_func_memcmp_working = no && case " $LIBOBJS " in
-  *" memcmp.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS memcmp.$ac_objext"
- ;;
-esac
-
-
 
-
-for ac_header in stdlib.h unistd.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
+  if test "x$ac_ct_RANLIB" = x; then
+    RANLIB=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
+    RANLIB=$ac_ct_RANLIB
+  fi
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_header_compiler=no
+  RANLIB="$ac_cv_prog_RANLIB"
 fi
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
+# Extract the first word of "cflow", so it can be a program name with args.
+set dummy cflow; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_path_CFLOW_CMD+set}" = set; then :
+  $as_echo_n "(cached) " >&6
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  case $CFLOW_CMD in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_CFLOW_CMD="$CFLOW_CMD" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_CFLOW_CMD="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
-  ac_header_preproc=no
+  ;;
+esac
+fi
+CFLOW_CMD=$ac_cv_path_CFLOW_CMD
+if test -n "$CFLOW_CMD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CFLOW_CMD" >&5
+$as_echo "$CFLOW_CMD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+# Extract the first word of "cscope", so it can be a program name with args.
+set dummy cscope; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_path_CSCOPE_CMD+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  eval "$as_ac_Header=\$ac_header_preproc"
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+  case $CSCOPE_CMD in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_CSCOPE_CMD="$CSCOPE_CMD" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_CSCOPE_CMD="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
+  ;;
+esac
 fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
+CSCOPE_CMD=$ac_cv_path_CSCOPE_CMD
+if test -n "$CSCOPE_CMD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CSCOPE_CMD" >&5
+$as_echo "$CSCOPE_CMD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
-done
 
 
-for ac_func in getpagesize
-do
-as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
-$as_echo_n "checking for $ac_func... " >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+################################################################################
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do
+  as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5
+$as_echo_n "checking for $ac_hdr that defines DIR... " >&6; }
+if eval "test \"\${$as_ac_Header+set}\"" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef $ac_func
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $ac_func ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub_$ac_func || defined __stub___$ac_func
-choke me
-#endif
+#include <sys/types.h>
+#include <$ac_hdr>
 
 int
 main ()
 {
-return $ac_func ();
+if ((DIR *) 0)
+return 0;
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  eval "$as_ac_var=yes"
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$as_ac_Header=yes"
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       eval "$as_ac_var=no"
+  eval "$as_ac_Header=no"
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-ac_res=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+eval ac_res=\$$as_ac_Header
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
 $as_echo "$ac_res" >&6; }
-as_val=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
   cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+#define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1
 _ACEOF
 
+ac_header_dirent=$ac_hdr; break
 fi
-done
 
-{ $as_echo "$as_me:$LINENO: checking for working mmap" >&5
-$as_echo_n "checking for working mmap... " >&6; }
-if test "${ac_cv_func_mmap_fixed_mapped+set}" = set; then
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
+$as_echo_n "checking for library containing opendir... " >&6; }
+if test "${ac_cv_search_opendir+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  if test "$cross_compiling" = yes; then
-  ac_cv_func_mmap_fixed_mapped=no
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_includes_default
-/* malloc might have been renamed as rpl_malloc. */
-#undef malloc
-
-/* Thanks to Mike Haertel and Jim Avera for this test.
-   Here is a matrix of mmap possibilities:
-       mmap private not fixed
-       mmap private fixed at somewhere currently unmapped
-       mmap private fixed at somewhere already mapped
-       mmap shared not fixed
-       mmap shared fixed at somewhere currently unmapped
-       mmap shared fixed at somewhere already mapped
-   For private mappings, we should verify that changes cannot be read()
-   back from the file, nor mmap's back from the file at a different
-   address.  (There have been systems where private was not correctly
-   implemented like the infamous i386 svr4.0, and systems where the
-   VM page cache was not coherent with the file system buffer cache
-   like early versions of FreeBSD and possibly contemporary NetBSD.)
-   For shared mappings, we should conversely verify that changes get
-   propagated back to all the places they're supposed to be.
-
-   Grep wants private fixed already mapped.
-   The main things grep needs to know about mmap are:
-   * does it exist and is it safe to write into the mmap'd area
-   * how to use it (BSD variants)  */
-
-#include <fcntl.h>
-#include <sys/mman.h>
 
-#if !defined STDC_HEADERS && !defined HAVE_STDLIB_H
-char *malloc ();
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
 #endif
-
-/* This mess was copied from the GNU getpagesize.h.  */
-#ifndef HAVE_GETPAGESIZE
-/* Assume that all systems that can run configure have sys/param.h.  */
-# ifndef HAVE_SYS_PARAM_H
-#  define HAVE_SYS_PARAM_H 1
-# endif
-
-# ifdef _SC_PAGESIZE
-#  define getpagesize() sysconf(_SC_PAGESIZE)
-# else /* no _SC_PAGESIZE */
-#  ifdef HAVE_SYS_PARAM_H
-#   include <sys/param.h>
-#   ifdef EXEC_PAGESIZE
-#    define getpagesize() EXEC_PAGESIZE
-#   else /* no EXEC_PAGESIZE */
-#    ifdef NBPG
-#     define getpagesize() NBPG * CLSIZE
-#     ifndef CLSIZE
-#      define CLSIZE 1
-#     endif /* no CLSIZE */
-#    else /* no NBPG */
-#     ifdef NBPC
-#      define getpagesize() NBPC
-#     else /* no NBPC */
-#      ifdef PAGESIZE
-#       define getpagesize() PAGESIZE
-#      endif /* PAGESIZE */
-#     endif /* no NBPC */
-#    endif /* no NBPG */
-#   endif /* no EXEC_PAGESIZE */
-#  else /* no HAVE_SYS_PARAM_H */
-#   define getpagesize() 8192  /* punt totally */
-#  endif /* no HAVE_SYS_PARAM_H */
-# endif /* no _SC_PAGESIZE */
-
-#endif /* no HAVE_GETPAGESIZE */
-
+char opendir ();
 int
 main ()
 {
-  char *data, *data2, *data3;
-  int i, pagesize;
-  int fd;
-
-  pagesize = getpagesize ();
-
-  /* First, make a file with some known garbage in it. */
-  data = (char *) malloc (pagesize);
-  if (!data)
-    return 1;
-  for (i = 0; i < pagesize; ++i)
-    *(data + i) = rand ();
-  umask (0);
-  fd = creat ("conftest.mmap", 0600);
-  if (fd < 0)
-    return 1;
-  if (write (fd, data, pagesize) != pagesize)
-    return 1;
-  close (fd);
-
-  /* Next, try to mmap the file at a fixed address which already has
-     something else allocated at it.  If we can, also make sure that
-     we see the same garbage.  */
-  fd = open ("conftest.mmap", O_RDWR);
-  if (fd < 0)
-    return 1;
-  data2 = (char *) malloc (2 * pagesize);
-  if (!data2)
-    return 1;
-  data2 += (pagesize - ((long int) data2 & (pagesize - 1))) & (pagesize - 1);
-  if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE,
-                    MAP_PRIVATE | MAP_FIXED, fd, 0L))
-    return 1;
-  for (i = 0; i < pagesize; ++i)
-    if (*(data + i) != *(data2 + i))
-      return 1;
-
-  /* Finally, make sure that changes to the mapped area do not
-     percolate back to the file as seen by read().  (This is a bug on
-     some variants of i386 svr4.0.)  */
-  for (i = 0; i < pagesize; ++i)
-    *(data2 + i) = *(data2 + i) + 1;
-  data3 = (char *) malloc (pagesize);
-  if (!data3)
-    return 1;
-  if (read (fd, data3, pagesize) != pagesize)
-    return 1;
-  for (i = 0; i < pagesize; ++i)
-    if (*(data + i) != *(data3 + i))
-      return 1;
-  close (fd);
+return opendir ();
+  ;
   return 0;
 }
 _ACEOF
-rm -f conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_cv_func_mmap_fixed_mapped=yes
-else
-  $as_echo "$as_me: program exited with status $ac_status" >&5
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-( exit $ac_status )
-ac_cv_func_mmap_fixed_mapped=no
+for ac_lib in '' dir; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_opendir=$ac_res
 fi
-rm -rf conftest.dSYM
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if test "${ac_cv_search_opendir+set}" = set; then :
+  break
 fi
+done
+if test "${ac_cv_search_opendir+set}" = set; then :
 
-
+else
+  ac_cv_search_opendir=no
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_mmap_fixed_mapped" >&5
-$as_echo "$ac_cv_func_mmap_fixed_mapped" >&6; }
-if test $ac_cv_func_mmap_fixed_mapped = yes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_MMAP 1
-_ACEOF
-
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
 fi
-rm -f conftest.mmap
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5
+$as_echo "$ac_cv_search_opendir" >&6; }
+ac_res=$ac_cv_search_opendir
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
 
+fi
 
-for ac_header in stdlib.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
+$as_echo_n "checking for library containing opendir... " >&6; }
+if test "${ac_cv_search_opendir+set}" = set; then :
   $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char opendir ();
+int
+main ()
+{
+return opendir ();
+  ;
+  return 0;
+}
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
+for ac_lib in '' x; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_opendir=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if test "${ac_cv_search_opendir+set}" = set; then :
+  break
+fi
+done
+if test "${ac_cv_search_opendir+set}" = set; then :
+
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  ac_cv_search_opendir=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5
+$as_echo "$ac_cv_search_opendir" >&6; }
+ac_res=$ac_cv_search_opendir
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
 
-       ac_header_compiler=no
 fi
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
+fi
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-#include <$ac_header>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
 _ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  ac_header_preproc=no
+  ac_cv_header_stdc=no
 fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
 
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
 else
-  eval "$as_ac_Header=\$ac_header_preproc"
+  ac_cv_header_stdc=no
 fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+rm -f conftest*
 
 fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
 _ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
 
+else
+  ac_cv_header_stdc=no
 fi
+rm -f conftest*
 
-done
+fi
 
-{ $as_echo "$as_me:$LINENO: checking for GNU libc compatible realloc" >&5
-$as_echo_n "checking for GNU libc compatible realloc... " >&6; }
-if test "${ac_cv_func_realloc_0_nonnull+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  if test "$cross_compiling" = yes; then
-  ac_cv_func_realloc_0_nonnull=no
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-#if defined STDC_HEADERS || defined HAVE_STDLIB_H
-# include <stdlib.h>
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
 #else
-char *realloc ();
+# define ISLOWER(c) \
+                  (('a' <= (c) && (c) <= 'i') \
+                    || ('j' <= (c) && (c) <= 'r') \
+                    || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
 #endif
 
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
 int
 main ()
 {
-return ! realloc (0, 0);
-  ;
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+       || toupper (i) != TOUPPER (i))
+      return 2;
   return 0;
 }
 _ACEOF
-rm -f conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_cv_func_realloc_0_nonnull=yes
-else
-  $as_echo "$as_me: program exited with status $ac_status" >&5
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+if ac_fn_c_try_run "$LINENO"; then :
 
-( exit $ac_status )
-ac_cv_func_realloc_0_nonnull=no
+else
+  ac_cv_header_stdc=no
 fi
-rm -rf conftest.dSYM
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
 fi
 
-
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_realloc_0_nonnull" >&5
-$as_echo "$ac_cv_func_realloc_0_nonnull" >&6; }
-if test $ac_cv_func_realloc_0_nonnull = yes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_REALLOC 1
-_ACEOF
-
-else
-  cat >>confdefs.h <<\_ACEOF
-#define HAVE_REALLOC 0
-_ACEOF
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
 
-   case " $LIBOBJS " in
-  *" realloc.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS realloc.$ac_objext"
- ;;
-esac
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
 
+fi
 
-cat >>confdefs.h <<\_ACEOF
-#define realloc rpl_realloc
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+                 inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
 _ACEOF
 
 fi
 
+done
 
 
-{ $as_echo "$as_me:$LINENO: checking whether stat accepts an empty string" >&5
-$as_echo_n "checking whether stat accepts an empty string... " >&6; }
-if test "${ac_cv_func_stat_empty_string_bug+set}" = set; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sys/types.h defines makedev" >&5
+$as_echo_n "checking whether sys/types.h defines makedev... " >&6; }
+if test "${ac_cv_header_sys_types_h_makedev+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  if test "$cross_compiling" = yes; then
-  ac_cv_func_stat_empty_string_bug=yes
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_includes_default
+#include <sys/types.h>
 int
 main ()
 {
-struct stat sbuf;
-  return stat ("", &sbuf) == 0;
+return makedev(0, 0);
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_cv_func_stat_empty_string_bug=no
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_header_sys_types_h_makedev=yes
 else
-  $as_echo "$as_me: program exited with status $ac_status" >&5
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-( exit $ac_status )
-ac_cv_func_stat_empty_string_bug=yes
+  ac_cv_header_sys_types_h_makedev=no
 fi
-rm -rf conftest.dSYM
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_types_h_makedev" >&5
+$as_echo "$ac_cv_header_sys_types_h_makedev" >&6; }
+
+if test $ac_cv_header_sys_types_h_makedev = no; then
+ac_fn_c_check_header_mongrel "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_mkdev_h" = x""yes; then :
 
+$as_echo "#define MAJOR_IN_MKDEV 1" >>confdefs.h
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_stat_empty_string_bug" >&5
-$as_echo "$ac_cv_func_stat_empty_string_bug" >&6; }
-if test $ac_cv_func_stat_empty_string_bug = yes; then
-  case " $LIBOBJS " in
-  *" stat.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS stat.$ac_objext"
- ;;
-esac
 
 
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STAT_EMPTY_STRING_BUG 1
-_ACEOF
 
+  if test $ac_cv_header_sys_mkdev_h = no; then
+    ac_fn_c_check_header_mongrel "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_sysmacros_h" = x""yes; then :
+
+$as_echo "#define MAJOR_IN_SYSMACROS 1" >>confdefs.h
+
+fi
+
+
+  fi
 fi
 
-{ $as_echo "$as_me:$LINENO: checking for working strtod" >&5
-$as_echo_n "checking for working strtod... " >&6; }
-if test "${ac_cv_func_strtod+set}" = set; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  if test "$cross_compiling" = yes; then
-  ac_cv_func_strtod=no
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
 
-$ac_includes_default
-#ifndef strtod
-double strtod ();
-#endif
 int
-main()
+main ()
 {
-  {
-    /* Some versions of Linux strtod mis-parse strings with leading '+'.  */
-    char *string = " +69";
-    char *term;
-    double value;
-    value = strtod (string, &term);
-    if (value != 69 || term != (string + 4))
-      return 1;
-  }
 
-  {
-    /* Under Solaris 2.4, strtod returns the wrong value for the
-       terminating character under some conditions.  */
-    char *string = "NaN";
-    char *term;
-    strtod (string, &term);
-    if (term != string && *(term - 1) == 0)
-      return 1;
-  }
+  ;
   return 0;
 }
-
 _ACEOF
-rm -f conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_cv_func_strtod=yes
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
 else
-  $as_echo "$as_me: program exited with status $ac_status" >&5
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-( exit $ac_status )
-ac_cv_func_strtod=no
-fi
-rm -rf conftest.dSYM
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+  ac_cv_header_stdc=no
 fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
 
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_strtod" >&5
-$as_echo "$ac_cv_func_strtod" >&6; }
-if test $ac_cv_func_strtod = no; then
-  case " $LIBOBJS " in
-  *" strtod.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS strtod.$ac_objext"
- ;;
-esac
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
 
-{ $as_echo "$as_me:$LINENO: checking for pow" >&5
-$as_echo_n "checking for pow... " >&6; }
-if test "${ac_cv_func_pow+set}" = set; then
-  $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-/* Define pow to an innocuous variant, in case <limits.h> declares pow.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define pow innocuous_pow
+#include <stdlib.h>
 
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char pow (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
 
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
 
-#undef pow
+fi
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char pow ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub_pow || defined __stub___pow
-choke me
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+                  (('a' <= (c) && (c) <= 'i') \
+                    || ('j' <= (c) && (c) <= 'r') \
+                    || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
 #endif
 
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
 int
 main ()
 {
-return pow ();
-  ;
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+       || toupper (i) != TOUPPER (i))
+      return 2;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_func_pow=yes
+if ac_fn_c_try_run "$LINENO"; then :
+
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
 
-       ac_cv_func_pow=no
 fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
 
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_pow" >&5
-$as_echo "$ac_cv_func_pow" >&6; }
 
-if test $ac_cv_func_pow = no; then
-  { $as_echo "$as_me:$LINENO: checking for pow in -lm" >&5
-$as_echo_n "checking for pow in -lm... " >&6; }
-if test "${ac_cv_lib_m_pow+set}" = set; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5
+$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; }
+if test "${ac_cv_header_sys_wait_h+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lm  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8)
 #endif
-char pow ();
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
 int
 main ()
 {
-return pow ();
+  int s;
+  wait (&s);
+  s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_lib_m_pow=yes
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_sys_wait_h=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_lib_m_pow=no
-fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+  ac_cv_header_sys_wait_h=no
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_m_pow" >&5
-$as_echo "$ac_cv_lib_m_pow" >&6; }
-if test "x$ac_cv_lib_m_pow" = x""yes; then
-  POW_LIB=-lm
-else
-  { $as_echo "$as_me:$LINENO: WARNING: cannot find library containing definition of pow" >&5
-$as_echo "$as_me: WARNING: cannot find library containing definition of pow" >&2;}
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5
+$as_echo "$ac_cv_header_sys_wait_h" >&6; }
+if test $ac_cv_header_sys_wait_h = yes; then
 
-fi
+$as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h
 
 fi
 
-
-for ac_func in vprintf
-do
-as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
-$as_echo_n "checking for $ac_func... " >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5
+$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; }
+if test "${ac_cv_header_time+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef $ac_func
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $ac_func ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub_$ac_func || defined __stub___$ac_func
-choke me
-#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
 
 int
 main ()
 {
-return $ac_func ();
+if ((struct tm *) 0)
+return 0;
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  eval "$as_ac_var=yes"
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_time=yes
+else
+  ac_cv_header_time=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5
+$as_echo "$ac_cv_header_time" >&6; }
+if test $ac_cv_header_time = yes; then
+
+$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h
+
+fi
+
+
+for ac_header in locale.h stddef.h syslog.h sys/file.h sys/time.h assert.h \
+  langinfo.h libgen.h signal.h sys/mman.h sys/resource.h sys/utsname.h \
+  sys/wait.h time.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  as_fn_error $? "bailing out" "$LINENO" 5
+fi
+
+done
 
-       eval "$as_ac_var=no"
+
+case "$host_os" in
+       linux*)
+               for ac_header in asm/byteorder.h linux/fs.h malloc.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+else
+  as_fn_error $? "bailing out" "$LINENO" 5
 fi
 
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+done
+ ;;
+       darwin*)
+               for ac_header in machine/endian.h sys/disk.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+else
+  as_fn_error $? "bailing out" "$LINENO" 5
 fi
-ac_res=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-as_val=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
+
+done
+ ;;
+esac
+
+for ac_header in ctype.h dirent.h errno.h fcntl.h getopt.h inttypes.h limits.h \
+  stdarg.h stdio.h stdlib.h string.h sys/ioctl.h sys/param.h sys/stat.h \
+  sys/types.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
   cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
 _ACEOF
 
-{ $as_echo "$as_me:$LINENO: checking for _doprnt" >&5
-$as_echo_n "checking for _doprnt... " >&6; }
-if test "${ac_cv_func__doprnt+set}" = set; then
-  $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
+  as_fn_error $? "bailing out" "$LINENO" 5
+fi
+
+done
+
+for ac_header in termios.h sys/statvfs.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
 _ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-/* Define _doprnt to an innocuous variant, in case <limits.h> declares _doprnt.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define _doprnt innocuous__doprnt
 
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char _doprnt (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
+fi
 
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
+done
 
-#undef _doprnt
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char _doprnt ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub__doprnt || defined __stub____doprnt
-choke me
-#endif
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
+$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
+if test "${ac_cv_c_const+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
 
 int
 main ()
 {
-return _doprnt ();
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+  /* Ultrix mips cc rejects this.  */
+  typedef int charset[2];
+  const charset cs;
+  /* SunOS 4.1.1 cc rejects this.  */
+  char const *const *pcpcc;
+  char **ppc;
+  /* NEC SVR4.0.2 mips cc rejects this.  */
+  struct point {int x, y;};
+  static struct point const zero = {0,0};
+  /* AIX XL C 1.02.0.0 rejects this.
+     It does not let you subtract one const X* pointer from another in
+     an arm of an if-expression whose if-part is not a constant
+     expression */
+  const char *g = "string";
+  pcpcc = &g + (g ? g-g : 0);
+  /* HPUX 7.0 cc rejects these. */
+  ++pcpcc;
+  ppc = (char**) pcpcc;
+  pcpcc = (char const *const *) ppc;
+  { /* SCO 3.2v4 cc rejects this.  */
+    char *t;
+    char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+    *t++ = 0;
+    if (s) return 0;
+  }
+  { /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+    int x[] = {25, 17};
+    const int *foo = &x[0];
+    ++foo;
+  }
+  { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+    typedef const int *iptr;
+    iptr p = 0;
+    ++p;
+  }
+  { /* AIX XL C 1.02.0.0 rejects this saying
+       "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+    struct s { int j; const int *ap[3]; };
+    struct s *b; b->j = 5;
+  }
+  { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+    const int foo = 10;
+    if (!foo) return 0;
+  }
+  return !cs[0] && !zero.x;
+#endif
+
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_func__doprnt=yes
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_const=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_func__doprnt=no
+  ac_cv_c_const=no
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func__doprnt" >&5
-$as_echo "$ac_cv_func__doprnt" >&6; }
-if test "x$ac_cv_func__doprnt" = x""yes; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5
+$as_echo "$ac_cv_c_const" >&6; }
+if test $ac_cv_c_const = no; then
 
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_DOPRNT 1
-_ACEOF
+$as_echo "#define const /**/" >>confdefs.h
 
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
+$as_echo_n "checking for inline... " >&6; }
+if test "${ac_cv_c_inline+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_inline=$ac_kw
 fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  test "$ac_cv_c_inline" != no && break
 done
 
-
-
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to use static linking" >&5
-$as_echo_n "checking whether to use static linking... " >&6; }
-# Check whether --enable-static_link was given.
-if test "${enable_static_link+set}" = set; then
-  enableval=$enable_static_link; STATIC_LINK=$enableval
-else
-  STATIC_LINK=no
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
+$as_echo "$ac_cv_c_inline" >&6; }
 
-{ $as_echo "$as_me:$LINENO: result: $STATIC_LINK" >&5
-$as_echo "$STATIC_LINK" >&6; }
+case $ac_cv_c_inline in
+  inline | yes) ;;
+  *)
+    case $ac_cv_c_inline in
+      no) ac_val=;;
+      *) ac_val=$ac_cv_c_inline;;
+    esac
+    cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+    ;;
+esac
 
-################################################################################
+ac_fn_c_check_member "$LINENO" "struct stat" "st_rdev" "ac_cv_member_struct_stat_st_rdev" "$ac_includes_default"
+if test "x$ac_cv_member_struct_stat_st_rdev" = x""yes; then :
 
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_STAT_ST_RDEV 1
+_ACEOF
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking file owner" >&5
-$as_echo_n "checking file owner... " >&6; }
 
-# Check whether --with-user was given.
-if test "${with_user+set}" = set; then
-  withval=$with_user; OWNER=$withval
 fi
 
-{ $as_echo "$as_me:$LINENO: result: $OWNER" >&5
-$as_echo "$OWNER" >&6; }
+ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default"
+if test "x$ac_cv_type_off_t" = x""yes; then :
 
-if test x$OWNER != x; then
-       INSTALL="$INSTALL -o $OWNER"
-fi
+else
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking group owner" >&5
-$as_echo_n "checking group owner... " >&6; }
+cat >>confdefs.h <<_ACEOF
+#define off_t long int
+_ACEOF
 
-# Check whether --with-group was given.
-if test "${with_group+set}" = set; then
-  withval=$with_group; GROUP=$withval
 fi
 
-{ $as_echo "$as_me:$LINENO: result: $GROUP" >&5
-$as_echo "$GROUP" >&6; }
+ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default"
+if test "x$ac_cv_type_pid_t" = x""yes; then :
 
-if test x$GROUP != x; then
-       INSTALL="$INSTALL -g $GROUP"
-fi
+else
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking device node uid" >&5
-$as_echo_n "checking device node uid... " >&6; }
+cat >>confdefs.h <<_ACEOF
+#define pid_t int
+_ACEOF
 
+fi
 
-# Check whether --with-device-uid was given.
-if test "${with_device_uid+set}" = set; then
-  withval=$with_device_uid; DM_DEVICE_UID=$withval
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5
+$as_echo_n "checking return type of signal handlers... " >&6; }
+if test "${ac_cv_type_signal+set}" = set; then :
+  $as_echo_n "(cached) " >&6
 else
-  DM_DEVICE_UID=0
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <signal.h>
+
+int
+main ()
+{
+return *(signal (0, 0)) (0) == 1;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_type_signal=int
+else
+  ac_cv_type_signal=void
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5
+$as_echo "$ac_cv_type_signal" >&6; }
 
-{ $as_echo "$as_me:$LINENO: result: $DM_DEVICE_UID" >&5
-$as_echo "$DM_DEVICE_UID" >&6; }
+cat >>confdefs.h <<_ACEOF
+#define RETSIGTYPE $ac_cv_type_signal
+_ACEOF
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking device node gid" >&5
-$as_echo_n "checking device node gid... " >&6; }
 
+ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
+if test "x$ac_cv_type_size_t" = x""yes; then :
 
-# Check whether --with-device-gid was given.
-if test "${with_device_gid+set}" = set; then
-  withval=$with_device_gid; DM_DEVICE_GID=$withval
 else
-  DM_DEVICE_GID=0
-fi
-
-{ $as_echo "$as_me:$LINENO: result: $DM_DEVICE_GID" >&5
-$as_echo "$DM_DEVICE_GID" >&6; }
-
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking device node mode" >&5
-$as_echo_n "checking device node mode... " >&6; }
 
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned int
+_ACEOF
 
-# Check whether --with-device-mode was given.
-if test "${with_device_mode+set}" = set; then
-  withval=$with_device_mode; DM_DEVICE_MODE=$withval
-else
-  DM_DEVICE_MODE=0600
 fi
 
-{ $as_echo "$as_me:$LINENO: result: $DM_DEVICE_MODE" >&5
-$as_echo "$DM_DEVICE_MODE" >&6; }
+ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default"
+if test "x$ac_cv_type_mode_t" = x""yes; then :
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to enable lvm1 fallback" >&5
-$as_echo_n "checking whether to enable lvm1 fallback... " >&6; }
-# Check whether --enable-lvm1_fallback was given.
-if test "${enable_lvm1_fallback+set}" = set; then
-  enableval=$enable_lvm1_fallback; LVM1_FALLBACK=$enableval
 else
-  LVM1_FALLBACK=no
+
+cat >>confdefs.h <<_ACEOF
+#define mode_t int
+_ACEOF
+
 fi
 
-{ $as_echo "$as_me:$LINENO: result: $LVM1_FALLBACK" >&5
-$as_echo "$LVM1_FALLBACK" >&6; }
+ac_fn_c_find_intX_t "$LINENO" "8" "ac_cv_c_int8_t"
+case $ac_cv_c_int8_t in #(
+  no|yes) ;; #(
+  *)
 
-if test x$LVM1_FALLBACK = xyes; then
+cat >>confdefs.h <<_ACEOF
+#define int8_t $ac_cv_c_int8_t
+_ACEOF
+;;
+esac
+
+ac_fn_c_find_intX_t "$LINENO" "16" "ac_cv_c_int16_t"
+case $ac_cv_c_int16_t in #(
+  no|yes) ;; #(
+  *)
 
-cat >>confdefs.h <<\_ACEOF
-#define LVM1_FALLBACK 1
+cat >>confdefs.h <<_ACEOF
+#define int16_t $ac_cv_c_int16_t
 _ACEOF
+;;
+esac
 
-fi
+ac_fn_c_find_intX_t "$LINENO" "32" "ac_cv_c_int32_t"
+case $ac_cv_c_int32_t in #(
+  no|yes) ;; #(
+  *)
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to include support for lvm1 metadata" >&5
-$as_echo_n "checking whether to include support for lvm1 metadata... " >&6; }
+cat >>confdefs.h <<_ACEOF
+#define int32_t $ac_cv_c_int32_t
+_ACEOF
+;;
+esac
 
-# Check whether --with-lvm1 was given.
-if test "${with_lvm1+set}" = set; then
-  withval=$with_lvm1; LVM1=$withval
-else
-  LVM1=internal
-fi
+ac_fn_c_find_intX_t "$LINENO" "64" "ac_cv_c_int64_t"
+case $ac_cv_c_int64_t in #(
+  no|yes) ;; #(
+  *)
 
-{ $as_echo "$as_me:$LINENO: result: $LVM1" >&5
-$as_echo "$LVM1" >&6; }
+cat >>confdefs.h <<_ACEOF
+#define int64_t $ac_cv_c_int64_t
+_ACEOF
+;;
+esac
 
-if [ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ];
- then  { { $as_echo "$as_me:$LINENO: error: --with-lvm1 parameter invalid
-" >&5
-$as_echo "$as_me: error: --with-lvm1 parameter invalid
-" >&2;}
-   { (exit 1); exit 1; }; }
-fi;
+ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default"
+if test "x$ac_cv_type_ssize_t" = x""yes; then :
 
-if test x$LVM1 = xinternal; then
+else
 
-cat >>confdefs.h <<\_ACEOF
-#define LVM1_INTERNAL 1
+cat >>confdefs.h <<_ACEOF
+#define ssize_t int
 _ACEOF
 
 fi
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to include support for GFS pool metadata" >&5
-$as_echo_n "checking whether to include support for GFS pool metadata... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5
+$as_echo_n "checking for uid_t in sys/types.h... " >&6; }
+if test "${ac_cv_type_uid_t+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
 
-# Check whether --with-pool was given.
-if test "${with_pool+set}" = set; then
-  withval=$with_pool; POOL=$withval
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "uid_t" >/dev/null 2>&1; then :
+  ac_cv_type_uid_t=yes
 else
-  POOL=internal
+  ac_cv_type_uid_t=no
 fi
+rm -f conftest*
 
-{ $as_echo "$as_me:$LINENO: result: $POOL" >&5
-$as_echo "$POOL" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5
+$as_echo "$ac_cv_type_uid_t" >&6; }
+if test $ac_cv_type_uid_t = no; then
 
-if [ "x$POOL" != xnone -a "x$POOL" != xinternal -a "x$POOL" != xshared ];
- then  { { $as_echo "$as_me:$LINENO: error: --with-pool parameter invalid
-" >&5
-$as_echo "$as_me: error: --with-pool parameter invalid
-" >&2;}
-   { (exit 1); exit 1; }; }
-fi;
+$as_echo "#define uid_t int" >>confdefs.h
 
-if test x$POOL = xinternal; then
 
-cat >>confdefs.h <<\_ACEOF
-#define POOL_INTERNAL 1
-_ACEOF
+$as_echo "#define gid_t int" >>confdefs.h
 
 fi
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to include support for cluster locking" >&5
-$as_echo_n "checking whether to include support for cluster locking... " >&6; }
+ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t"
+case $ac_cv_c_uint8_t in #(
+  no|yes) ;; #(
+  *)
 
-# Check whether --with-cluster was given.
-if test "${with_cluster+set}" = set; then
-  withval=$with_cluster; CLUSTER=$withval
-fi
+$as_echo "#define _UINT8_T 1" >>confdefs.h
 
-{ $as_echo "$as_me:$LINENO: result: $CLUSTER" >&5
-$as_echo "$CLUSTER" >&6; }
 
-if [ "x$CLUSTER" != xnone -a "x$CLUSTER" != xinternal -a "x$CLUSTER" != xshared ];
- then  { { $as_echo "$as_me:$LINENO: error: --with-cluster parameter invalid
-" >&5
-$as_echo "$as_me: error: --with-cluster parameter invalid
-" >&2;}
-   { (exit 1); exit 1; }; }
-fi;
+cat >>confdefs.h <<_ACEOF
+#define uint8_t $ac_cv_c_uint8_t
+_ACEOF
+;;
+  esac
 
-if test x$CLUSTER = xinternal; then
+ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t"
+case $ac_cv_c_uint16_t in #(
+  no|yes) ;; #(
+  *)
 
-cat >>confdefs.h <<\_ACEOF
-#define CLUSTER_LOCKING_INTERNAL 1
+
+cat >>confdefs.h <<_ACEOF
+#define uint16_t $ac_cv_c_uint16_t
 _ACEOF
+;;
+  esac
 
-fi
+ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t"
+case $ac_cv_c_uint32_t in #(
+  no|yes) ;; #(
+  *)
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to include snapshots" >&5
-$as_echo_n "checking whether to include snapshots... " >&6; }
+$as_echo "#define _UINT32_T 1" >>confdefs.h
 
-# Check whether --with-snapshots was given.
-if test "${with_snapshots+set}" = set; then
-  withval=$with_snapshots; SNAPSHOTS=$withval
-else
-  SNAPSHOTS=internal
-fi
 
-{ $as_echo "$as_me:$LINENO: result: $SNAPSHOTS" >&5
-$as_echo "$SNAPSHOTS" >&6; }
+cat >>confdefs.h <<_ACEOF
+#define uint32_t $ac_cv_c_uint32_t
+_ACEOF
+;;
+  esac
 
-if [ "x$SNAPSHOTS" != xnone -a "x$SNAPSHOTS" != xinternal -a "x$SNAPSHOTS" != xshared ];
- then  { { $as_echo "$as_me:$LINENO: error: --with-snapshots parameter invalid
-" >&5
-$as_echo "$as_me: error: --with-snapshots parameter invalid
-" >&2;}
-   { (exit 1); exit 1; }; }
-fi;
+ac_fn_c_find_uintX_t "$LINENO" "64" "ac_cv_c_uint64_t"
+case $ac_cv_c_uint64_t in #(
+  no|yes) ;; #(
+  *)
 
-if test x$SNAPSHOTS = xinternal; then
+$as_echo "#define _UINT64_T 1" >>confdefs.h
+
+
+cat >>confdefs.h <<_ACEOF
+#define uint64_t $ac_cv_c_uint64_t
+_ACEOF
+;;
+  esac
+
+ac_fn_c_check_member "$LINENO" "struct stat" "st_rdev" "ac_cv_member_struct_stat_st_rdev" "$ac_includes_default"
+if test "x$ac_cv_member_struct_stat_st_rdev" = x""yes; then :
 
-cat >>confdefs.h <<\_ACEOF
-#define SNAPSHOT_INTERNAL 1
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_STAT_ST_RDEV 1
 _ACEOF
 
+
 fi
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to include mirrors" >&5
-$as_echo_n "checking whether to include mirrors... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5
+$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; }
+if test "${ac_cv_struct_tm+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <time.h>
 
-# Check whether --with-mirrors was given.
-if test "${with_mirrors+set}" = set; then
-  withval=$with_mirrors; MIRRORS=$withval
+int
+main ()
+{
+struct tm tm;
+                                    int *p = &tm.tm_sec;
+                                    return !p;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_struct_tm=time.h
 else
-  MIRRORS=internal
+  ac_cv_struct_tm=sys/time.h
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5
+$as_echo "$ac_cv_struct_tm" >&6; }
+if test $ac_cv_struct_tm = sys/time.h; then
 
-{ $as_echo "$as_me:$LINENO: result: $MIRRORS" >&5
-$as_echo "$MIRRORS" >&6; }
+$as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h
 
-if [ "x$MIRRORS" != xnone -a "x$MIRRORS" != xinternal -a "x$MIRRORS" != xshared ];
- then  { { $as_echo "$as_me:$LINENO: error: --with-mirrors parameter invalid
-" >&5
-$as_echo "$as_me: error: --with-mirrors parameter invalid
-" >&2;}
-   { (exit 1); exit 1; }; }
-fi;
+fi
 
-if test x$MIRRORS = xinternal; then
 
-cat >>confdefs.h <<\_ACEOF
-#define MIRRORED_INTERNAL 1
+################################################################################
+for ac_func in ftruncate gethostname getpagesize \
+  gettimeofday memset mkdir mkfifo rmdir munmap nl_langinfo setenv setlocale \
+  strcasecmp strchr strcspn strspn strdup strncasecmp strerror strrchr \
+  strstr strtol strtoul uname
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
 _ACEOF
 
+else
+  as_fn_error $? "bailing out" "$LINENO" 5
 fi
+done
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to include replicators" >&5
-$as_echo_n "checking whether to include replicators... " >&6; }
+for ac_func in siginterrupt
+do :
+  ac_fn_c_check_func "$LINENO" "siginterrupt" "ac_cv_func_siginterrupt"
+if test "x$ac_cv_func_siginterrupt" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SIGINTERRUPT 1
+_ACEOF
 
-# Check whether --with-replicators was given.
-if test "${with_replicators+set}" = set; then
-  withval=$with_replicators; REPLICATORS=$withval
+fi
+done
+
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments.  Useless!
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5
+$as_echo_n "checking for working alloca.h... " >&6; }
+if test "${ac_cv_working_alloca_h+set}" = set; then :
+  $as_echo_n "(cached) " >&6
 else
-  REPLICATORS=none
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <alloca.h>
+int
+main ()
+{
+char *p = (char *) alloca (2 * sizeof (int));
+                         if (p) return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_working_alloca_h=yes
+else
+  ac_cv_working_alloca_h=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5
+$as_echo "$ac_cv_working_alloca_h" >&6; }
+if test $ac_cv_working_alloca_h = yes; then
 
-{ $as_echo "$as_me:$LINENO: result: $REPLICATORS" >&5
-$as_echo "$REPLICATORS" >&6; }
+$as_echo "#define HAVE_ALLOCA_H 1" >>confdefs.h
 
-case "$REPLICATORS" in
-  none|shared) ;;
-  internal)
-cat >>confdefs.h <<\_ACEOF
-#define REPLICATOR_INTERNAL 1
-_ACEOF
- ;;
-  *) { { $as_echo "$as_me:$LINENO: error: --with-replicators parameter invalid ($REPLICATORS)" >&5
-$as_echo "$as_me: error: --with-replicators parameter invalid ($REPLICATORS)" >&2;}
-   { (exit 1); exit 1; }; } ;;
-esac
+fi
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to enable readline" >&5
-$as_echo_n "checking whether to enable readline... " >&6; }
-# Check whether --enable-readline was given.
-if test "${enable_readline+set}" = set; then
-  enableval=$enable_readline; READLINE=$enableval
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5
+$as_echo_n "checking for alloca... " >&6; }
+if test "${ac_cv_func_alloca_works+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# ifdef _MSC_VER
+#  include <malloc.h>
+#  define alloca _alloca
+# else
+#  ifdef HAVE_ALLOCA_H
+#   include <alloca.h>
+#  else
+#   ifdef _AIX
+ #pragma alloca
+#   else
+#    ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+int
+main ()
+{
+char *p = (char *) alloca (1);
+                                   if (p) return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_func_alloca_works=yes
 else
-  READLINE=maybe
+  ac_cv_func_alloca_works=no
 fi
-
-{ $as_echo "$as_me:$LINENO: result: $READLINE" >&5
-$as_echo "$READLINE" >&6; }
-
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to enable realtime support" >&5
-$as_echo_n "checking whether to enable realtime support... " >&6; }
-# Check whether --enable-realtime was given.
-if test "${enable_realtime+set}" = set; then
-  enableval=$enable_realtime; REALTIME=$enableval
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5
+$as_echo "$ac_cv_func_alloca_works" >&6; }
 
-{ $as_echo "$as_me:$LINENO: result: $REALTIME" >&5
-$as_echo "$REALTIME" >&6; }
+if test $ac_cv_func_alloca_works = yes; then
+
+$as_echo "#define HAVE_ALLOCA 1" >>confdefs.h
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to enable OCF resource agents" >&5
-$as_echo_n "checking whether to enable OCF resource agents... " >&6; }
-# Check whether --enable-ocf was given.
-if test "${enable_ocf+set}" = set; then
-  enableval=$enable_ocf; OCF=$enableval
 else
-  OCF=no
-fi
+  # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+# that cause trouble.  Some versions do not even contain alloca or
+# contain a buggy version.  If you still want to use their alloca,
+# use ar to extract alloca.o from them instead of compiling alloca.c.
 
-{ $as_echo "$as_me:$LINENO: result: $OCF" >&5
-$as_echo "$OCF" >&6; }
+ALLOCA=\${LIBOBJDIR}alloca.$ac_objext
 
-################################################################################
-pkg_config_init() {
+$as_echo "#define C_ALLOCA 1" >>confdefs.h
 
 
-if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
-       if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
-set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_path_PKG_CONFIG+set}" = set; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether \`alloca.c' needs Cray hooks" >&5
+$as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; }
+if test "${ac_cv_os_cray+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  case $PKG_CONFIG in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#if defined CRAY && ! defined CRAY2
+webecray
+#else
+wenotbecray
+#endif
 
-  ;;
-esac
-fi
-PKG_CONFIG=$ac_cv_path_PKG_CONFIG
-if test -n "$PKG_CONFIG"; then
-  { $as_echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5
-$as_echo "$PKG_CONFIG" >&6; }
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "webecray" >/dev/null 2>&1; then :
+  ac_cv_os_cray=yes
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
+  ac_cv_os_cray=no
 fi
-
+rm -f conftest*
 
 fi
-if test -z "$ac_cv_path_PKG_CONFIG"; then
-  ac_pt_PKG_CONFIG=$PKG_CONFIG
-  # Extract the first word of "pkg-config", so it can be a program name with args.
-set dummy pkg-config; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  case $ac_pt_PKG_CONFIG in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_os_cray" >&5
+$as_echo "$ac_cv_os_cray" >&6; }
+if test $ac_cv_os_cray = yes; then
+  for ac_func in _getb67 GETB67 getb67; do
+    as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
 
-  ;;
-esac
+cat >>confdefs.h <<_ACEOF
+#define CRAY_STACKSEG_END $ac_func
+_ACEOF
+
+    break
 fi
-ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
-if test -n "$ac_pt_PKG_CONFIG"; then
-  { $as_echo "$as_me:$LINENO: result: $ac_pt_PKG_CONFIG" >&5
-$as_echo "$ac_pt_PKG_CONFIG" >&6; }
-else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
+
+  done
 fi
 
-  if test "x$ac_pt_PKG_CONFIG" = x; then
-    PKG_CONFIG=""
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5
+$as_echo_n "checking stack direction for C alloca... " >&6; }
+if test "${ac_cv_c_stack_direction+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  ac_cv_c_stack_direction=0
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+int
+find_stack_direction ()
+{
+  static char *addr = 0;
+  auto char dummy;
+  if (addr == 0)
+    {
+      addr = &dummy;
+      return find_stack_direction ();
+    }
   else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    PKG_CONFIG=$ac_pt_PKG_CONFIG
-  fi
+    return (&dummy > addr) ? 1 : -1;
+}
+
+int
+main ()
+{
+  return find_stack_direction () < 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_c_stack_direction=1
 else
-  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+  ac_cv_c_stack_direction=-1
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
 fi
 
 fi
-if test -n "$PKG_CONFIG"; then
-       _pkg_min_version=0.9.0
-       { $as_echo "$as_me:$LINENO: checking pkg-config is at least version $_pkg_min_version" >&5
-$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
-       if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
-               { $as_echo "$as_me:$LINENO: result: yes" >&5
-$as_echo "yes" >&6; }
-       else
-               { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-               PKG_CONFIG=""
-       fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5
+$as_echo "$ac_cv_c_stack_direction" >&6; }
+cat >>confdefs.h <<_ACEOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+_ACEOF
+
 
 fi
 
-pkg_failed=no
-{ $as_echo "$as_me:$LINENO: checking for PKGCONFIGINIT" >&5
-$as_echo_n "checking for PKGCONFIGINIT... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether closedir returns void" >&5
+$as_echo_n "checking whether closedir returns void... " >&6; }
+if test "${ac_cv_func_closedir_void+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  ac_cv_func_closedir_void=yes
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header_dirent>
+#ifndef __cplusplus
+int closedir ();
+#endif
 
-if test -n "$PKGCONFIGINIT_CFLAGS"; then
-    pkg_cv_PKGCONFIGINIT_CFLAGS="$PKGCONFIGINIT_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"pkgconfiginit\"") >&5
-  ($PKG_CONFIG --exists --print-errors "pkgconfiginit") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_PKGCONFIGINIT_CFLAGS=`$PKG_CONFIG --cflags "pkgconfiginit" 2>/dev/null`
+int
+main ()
+{
+return closedir (opendir (".")) != 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_func_closedir_void=no
 else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
+  ac_cv_func_closedir_void=yes
 fi
-if test -n "$PKGCONFIGINIT_LIBS"; then
-    pkg_cv_PKGCONFIGINIT_LIBS="$PKGCONFIGINIT_LIBS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"pkgconfiginit\"") >&5
-  ($PKG_CONFIG --exists --print-errors "pkgconfiginit") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_PKGCONFIGINIT_LIBS=`$PKG_CONFIG --libs "pkgconfiginit" 2>/dev/null`
-else
-  pkg_failed=yes
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
 fi
- else
-    pkg_failed=untried
+
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_closedir_void" >&5
+$as_echo "$ac_cv_func_closedir_void" >&6; }
+if test $ac_cv_func_closedir_void = yes; then
 
+$as_echo "#define CLOSEDIR_VOID 1" >>confdefs.h
 
+fi
 
-if test $pkg_failed = yes; then
+for ac_header in unistd.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default"
+if test "x$ac_cv_header_unistd_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_UNISTD_H 1
+_ACEOF
 
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
-else
-        _pkg_short_errors_supported=no
 fi
-        if test $_pkg_short_errors_supported = yes; then
-               PKGCONFIGINIT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "pkgconfiginit" 2>&1`
-        else
-               PKGCONFIGINIT_PKG_ERRORS=`$PKG_CONFIG --print-errors "pkgconfiginit" 2>&1`
-        fi
-       # Put the nasty error message in config.log where it belongs
-       echo "$PKGCONFIGINIT_PKG_ERRORS" >&5
 
-       { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-                { $as_echo "$as_me:$LINENO: result: pkg-config initialized" >&5
-$as_echo "pkg-config initialized" >&6; }
-elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:$LINENO: result: pkg-config initialized" >&5
-$as_echo "pkg-config initialized" >&6; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working chown" >&5
+$as_echo_n "checking for working chown... " >&6; }
+if test "${ac_cv_func_chown_works+set}" = set; then :
+  $as_echo_n "(cached) " >&6
 else
-       PKGCONFIGINIT_CFLAGS=$pkg_cv_PKGCONFIGINIT_CFLAGS
-       PKGCONFIGINIT_LIBS=$pkg_cv_PKGCONFIGINIT_LIBS
-        { $as_echo "$as_me:$LINENO: result: yes" >&5
-$as_echo "yes" >&6; }
-       :
-fi
-       PKGCONFIG_INIT=1
-}
+  if test "$cross_compiling" = yes; then :
+  ac_cv_func_chown_works=no
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+#include <fcntl.h>
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to build cluster LVM daemon" >&5
-$as_echo_n "checking whether to build cluster LVM daemon... " >&6; }
+int
+main ()
+{
+  char *f = "conftest.chown";
+  struct stat before, after;
+
+  if (creat (f, 0600) < 0)
+    return 1;
+  if (stat (f, &before) < 0)
+    return 1;
+  if (chown (f, (uid_t) -1, (gid_t) -1) == -1)
+    return 1;
+  if (stat (f, &after) < 0)
+    return 1;
+  return ! (before.st_uid == after.st_uid && before.st_gid == after.st_gid);
 
-# Check whether --with-clvmd was given.
-if test "${with_clvmd+set}" = set; then
-  withval=$with_clvmd; CLVMD=$withval
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_func_chown_works=yes
 else
-  CLVMD=none
+  ac_cv_func_chown_works=no
 fi
-
-if test x$CLVMD = xyes; then
-       CLVMD=all
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
 fi
-{ $as_echo "$as_me:$LINENO: result: $CLVMD" >&5
-$as_echo "$CLVMD" >&6; }
 
-if  test x$CLVMD != xnone && test x$CLUSTER = xnone; then
-       CLUSTER=internal
-fi
+rm -f conftest.chown
 
-if test x$CLVMD != xnone && test x$PKGCONFIG_INIT != x1; then
-       pkg_config_init
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_chown_works" >&5
+$as_echo "$ac_cv_func_chown_works" >&6; }
+if test $ac_cv_func_chown_works = yes; then
 
-CLVMD_CMANAGERS=""
-CLVMD_NEEDS_QDISKD=no
+$as_echo "#define HAVE_CHOWN 1" >>confdefs.h
 
-if [ `expr x"$CLVMD" : '.*gulm.*'` != 0 ]; then
-       BUILDGULM=yes
-       CLVMD_CMANAGERS="$CLVMD_CMANAGERS lock_gulmd"
-       CLVMD_NEEDS_QDISKD=yes
-fi
-if [ `expr x"$CLVMD" : '.*cman.*'` != 0 ]; then
-       BUILDCMAN=yes
-       CLVMD_CMANAGERS="$CLVMD_CMANAGERS cman"
-       CLVMD_NEEDS_QDISKD=yes
-fi
-if [ `expr x"$CLVMD" : '.*corosync.*'` != 0 ]; then
-       BUILDCOROSYNC=yes
-       CLVMD_CMANAGERS="$CLVMD_CMANAGERS corosync"
-fi
-if [ `expr x"$CLVMD" : '.*openais.*'` != 0 ]; then
-       BUILDOPENAIS=yes
-       CLVMD_CMANAGERS="$CLVMD_CMANAGERS openais"
-fi
-if test x$CLVMD_NEEDS_QDISKD != xno; then
-       CLVMD_CMANAGERS="$CLVMD_CMANAGERS qdiskd"
 fi
 
-if test x$BUILDGULM = xyes; then
-       if test x$BUILDCOROSYNC = xyes || \
-          test x$BUILDOPENAIS = xyes; then
-               { { $as_echo "$as_me:$LINENO: error: requested clvmd configuration is not valid" >&5
-$as_echo "$as_me: error: requested clvmd configuration is not valid" >&2;}
-   { (exit 1); exit 1; }; }
-       fi
+for ac_header in vfork.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default"
+if test "x$ac_cv_header_vfork_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_VFORK_H 1
+_ACEOF
+
 fi
 
-soft_bailout() {
-       NOTFOUND=1
-}
+done
 
-hard_bailout() {
-       { { $as_echo "$as_me:$LINENO: error: bailing out" >&5
-$as_echo "$as_me: error: bailing out" >&2;}
-   { (exit 1); exit 1; }; }
-}
+for ac_func in fork vfork
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
 
-if test x$CLVMD = xall; then
-       bailout=soft_bailout
-       BUILDGULM=yes
-       BUILDCMAN=yes
-       BUILDCOROSYNC=yes
-       BUILDOPENAIS=yes
-else
-       bailout=hard_bailout
 fi
+done
 
-check_lib_no_libs() {
-       lib_no_libs_arg1=$1
-       shift
-       lib_no_libs_arg2=$1
-       shift
-       lib_no_libs_args=$@
-
-as_ac_Lib=`$as_echo "ac_cv_lib_$lib_no_libs_arg1''_$lib_no_libs_arg2" | $as_tr_sh`
-{ $as_echo "$as_me:$LINENO: checking for $lib_no_libs_arg2 in -l$lib_no_libs_arg1" >&5
-$as_echo_n "checking for $lib_no_libs_arg2 in -l$lib_no_libs_arg1... " >&6; }
-if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then
+if test "x$ac_cv_func_fork" = xyes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5
+$as_echo_n "checking for working fork... " >&6; }
+if test "${ac_cv_func_fork_works+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-l$lib_no_libs_arg1 $lib_no_libs_args $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  if test "$cross_compiling" = yes; then :
+  ac_cv_func_fork_works=cross
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $lib_no_libs_arg2 ();
+$ac_includes_default
 int
 main ()
 {
-return $lib_no_libs_arg2 ();
+
+         /* By Ruediger Kuhlmann. */
+         return fork () < 0;
+
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  eval "$as_ac_Lib=yes"
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_func_fork_works=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       eval "$as_ac_Lib=no"
+  ac_cv_func_fork_works=no
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
 fi
-ac_res=`eval 'as_val=${'$as_ac_Lib'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-as_val=`eval 'as_val=${'$as_ac_Lib'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_LIB$lib_no_libs_arg1" | $as_tr_cpp` 1
-_ACEOF
 
-  LIBS="-l$lib_no_libs_arg1 $LIBS"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5
+$as_echo "$ac_cv_func_fork_works" >&6; }
 
 else
-  $bailout
+  ac_cv_func_fork_works=$ac_cv_func_fork
 fi
-
-       LIBS=$ac_check_lib_save_LIBS
+if test "x$ac_cv_func_fork_works" = xcross; then
+  case $host in
+    *-*-amigaos* | *-*-msdosdjgpp*)
+      # Override, as these systems have only a dummy fork() stub
+      ac_cv_func_fork_works=no
+      ;;
+    *)
+      ac_cv_func_fork_works=yes
+      ;;
+  esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5
+$as_echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;}
+fi
+ac_cv_func_vfork_works=$ac_cv_func_vfork
+if test "x$ac_cv_func_vfork" = xyes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5
+$as_echo_n "checking for working vfork... " >&6; }
+if test "${ac_cv_func_vfork_works+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  ac_cv_func_vfork_works=cross
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Thanks to Paul Eggert for this test.  */
+$ac_includes_default
+#include <sys/wait.h>
+#ifdef HAVE_VFORK_H
+# include <vfork.h>
+#endif
+/* On some sparc systems, changes by the child to local and incoming
+   argument registers are propagated back to the parent.  The compiler
+   is told about this with #include <vfork.h>, but some compilers
+   (e.g. gcc -O) don't grok <vfork.h>.  Test for this by using a
+   static variable whose address is put into a register that is
+   clobbered by the vfork.  */
+static void
+#ifdef __cplusplus
+sparc_address_test (int arg)
+# else
+sparc_address_test (arg) int arg;
+#endif
+{
+  static pid_t child;
+  if (!child) {
+    child = vfork ();
+    if (child < 0) {
+      perror ("vfork");
+      _exit(2);
+    }
+    if (!child) {
+      arg = getpid();
+      write(-1, "", 0);
+      _exit (arg);
+    }
+  }
 }
 
-if test x$BUILDGULM = xyes; then
+int
+main ()
+{
+  pid_t parent = getpid ();
+  pid_t child;
 
-pkg_failed=no
-{ $as_echo "$as_me:$LINENO: checking for CCS" >&5
-$as_echo_n "checking for CCS... " >&6; }
+  sparc_address_test (0);
 
-if test -n "$CCS_CFLAGS"; then
-    pkg_cv_CCS_CFLAGS="$CCS_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libccs\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libccs") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_CCS_CFLAGS=`$PKG_CONFIG --cflags "libccs" 2>/dev/null`
+  child = vfork ();
+
+  if (child == 0) {
+    /* Here is another test for sparc vfork register problems.  This
+       test uses lots of local variables, at least as many local
+       variables as main has allocated so far including compiler
+       temporaries.  4 locals are enough for gcc 1.40.3 on a Solaris
+       4.1.3 sparc, but we use 8 to be safe.  A buggy compiler should
+       reuse the register of parent for one of the local variables,
+       since it will think that parent can't possibly be used any more
+       in this routine.  Assigning to the local variable will thus
+       munge parent in the parent process.  */
+    pid_t
+      p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(),
+      p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid();
+    /* Convince the compiler that p..p7 are live; otherwise, it might
+       use the same hardware register for all 8 local variables.  */
+    if (p != p1 || p != p2 || p != p3 || p != p4
+       || p != p5 || p != p6 || p != p7)
+      _exit(1);
+
+    /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent
+       from child file descriptors.  If the child closes a descriptor
+       before it execs or exits, this munges the parent's descriptor
+       as well.  Test for this by closing stdout in the child.  */
+    _exit(close(fileno(stdout)) != 0);
+  } else {
+    int status;
+    struct stat st;
+
+    while (wait(&status) != child)
+      ;
+    return (
+        /* Was there some problem with vforking?  */
+        child < 0
+
+        /* Did the child fail?  (This shouldn't happen.)  */
+        || status
+
+        /* Did the vfork/compiler bug occur?  */
+        || parent != getpid()
+
+        /* Did the file descriptor bug occur?  */
+        || fstat(fileno(stdout), &st) != 0
+        );
+  }
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_func_vfork_works=yes
 else
-  pkg_failed=yes
+  ac_cv_func_vfork_works=no
 fi
- else
-    pkg_failed=untried
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
 fi
-if test -n "$CCS_LIBS"; then
-    pkg_cv_CCS_LIBS="$CCS_LIBS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libccs\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libccs") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_CCS_LIBS=`$PKG_CONFIG --libs "libccs" 2>/dev/null`
-else
-  pkg_failed=yes
+
 fi
- else
-    pkg_failed=untried
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5
+$as_echo "$ac_cv_func_vfork_works" >&6; }
+
+fi;
+if test "x$ac_cv_func_fork_works" = xcross; then
+  ac_cv_func_vfork_works=$ac_cv_func_vfork
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5
+$as_echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;}
 fi
 
+if test "x$ac_cv_func_vfork_works" = xyes; then
 
+$as_echo "#define HAVE_WORKING_VFORK 1" >>confdefs.h
 
-if test $pkg_failed = yes; then
-
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
 else
-        _pkg_short_errors_supported=no
+
+$as_echo "#define vfork fork" >>confdefs.h
+
 fi
-        if test $_pkg_short_errors_supported = yes; then
-               CCS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libccs" 2>&1`
-        else
-               CCS_PKG_ERRORS=`$PKG_CONFIG --print-errors "libccs" 2>&1`
-        fi
-       # Put the nasty error message in config.log where it belongs
-       echo "$CCS_PKG_ERRORS" >&5
+if test "x$ac_cv_func_fork_works" = xyes; then
 
-       { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-                NOTFOUND=0
+$as_echo "#define HAVE_WORKING_FORK 1" >>confdefs.h
 
-for ac_header in ccs.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
 fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lstat correctly handles trailing slash" >&5
+$as_echo_n "checking whether lstat correctly handles trailing slash... " >&6; }
+if test "${ac_cv_func_lstat_dereferences_slashed_symlink+set}" = set; then :
+  $as_echo_n "(cached) " >&6
 else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  rm -f conftest.sym conftest.file
+echo >conftest.file
+if test "$as_ln_s" = "ln -s" && ln -s conftest.file conftest.sym; then
+  if test "$cross_compiling" = yes; then :
+  ac_cv_func_lstat_dereferences_slashed_symlink=no
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 $ac_includes_default
-#include <$ac_header>
+int
+main ()
+{
+struct stat sbuf;
+     /* Linux will dereference the symlink and fail, as required by POSIX.
+       That is better in the sense that it means we will not
+       have to compile and use the lstat wrapper.  */
+     return lstat ("conftest.sym/", &sbuf) == 0;
+  ;
+  return 0;
+}
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_func_lstat_dereferences_slashed_symlink=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  ac_cv_func_lstat_dereferences_slashed_symlink=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+else
+  # If the `ln -s' command failed, then we probably don't even
+  # have an lstat function.
+  ac_cv_func_lstat_dereferences_slashed_symlink=no
+fi
+rm -f conftest.sym conftest.file
 
-       ac_header_compiler=no
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_lstat_dereferences_slashed_symlink" >&5
+$as_echo "$ac_cv_func_lstat_dereferences_slashed_symlink" >&6; }
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
+test $ac_cv_func_lstat_dereferences_slashed_symlink = yes &&
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
+cat >>confdefs.h <<_ACEOF
+#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1
 _ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+
+
+if test "x$ac_cv_func_lstat_dereferences_slashed_symlink" = xno; then
+  case " $LIBOBJS " in
+  *" lstat.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS lstat.$ac_objext"
+ ;;
+esac
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lstat accepts an empty string" >&5
+$as_echo_n "checking whether lstat accepts an empty string... " >&6; }
+if test "${ac_cv_func_lstat_empty_string_bug+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  ac_cv_func_lstat_empty_string_bug=yes
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-#include <$ac_header>
+$ac_includes_default
+int
+main ()
+{
+struct stat sbuf;
+  return lstat ("", &sbuf) == 0;
+  ;
+  return 0;
+}
 _ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_func_lstat_empty_string_bug=no
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  ac_cv_func_lstat_empty_string_bug=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
 
-  ac_header_preproc=no
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_lstat_empty_string_bug" >&5
+$as_echo "$ac_cv_func_lstat_empty_string_bug" >&6; }
+if test $ac_cv_func_lstat_empty_string_bug = yes; then
+  case " $LIBOBJS " in
+  *" lstat.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS lstat.$ac_objext"
+ ;;
+esac
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
 
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LSTAT_EMPTY_STRING_BUG 1
+_ACEOF
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  eval "$as_ac_Header=\$ac_header_preproc"
 fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 
-fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
+for ac_header in stdlib.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default"
+if test "x$ac_cv_header_stdlib_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+#define HAVE_STDLIB_H 1
 _ACEOF
 
-else
-  $bailout
 fi
 
 done
 
-               check_lib_no_libs ccs ccs_connect
-               if test $NOTFOUND = 0; then
-                       { $as_echo "$as_me:$LINENO: result: no pkg for libccs, using -lccs" >&5
-$as_echo "no pkg for libccs, using -lccs" >&6; }
-                       CCS_LIBS="-lccs"
-                       HAVE_CCS=yes
-               fi
-elif test $pkg_failed = untried; then
-       NOTFOUND=0
-
-for ac_header in ccs.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5
+$as_echo_n "checking for GNU libc compatible malloc... " >&6; }
+if test "${ac_cv_func_malloc_0_nonnull+set}" = set; then :
   $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  if test "$cross_compiling" = yes; then :
+  ac_cv_func_malloc_0_nonnull=no
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
+#if defined STDC_HEADERS || defined HAVE_STDLIB_H
+# include <stdlib.h>
+#else
+char *malloc ();
+#endif
+
+int
+main ()
+{
+return ! malloc (0);
+  ;
+  return 0;
+}
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_func_malloc_0_nonnull=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  ac_cv_func_malloc_0_nonnull=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
 
-       ac_header_compiler=no
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5
+$as_echo "$ac_cv_func_malloc_0_nonnull" >&6; }
+if test $ac_cv_func_malloc_0_nonnull = yes; then :
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
+$as_echo "#define HAVE_MALLOC 1" >>confdefs.h
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  $as_echo "#define HAVE_MALLOC 0" >>confdefs.h
 
-  ac_header_preproc=no
-fi
+   case " $LIBOBJS " in
+  *" malloc.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS malloc.$ac_objext"
+ ;;
+esac
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
 
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+$as_echo "#define malloc rpl_malloc" >>confdefs.h
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  eval "$as_ac_Header=\$ac_header_preproc"
 fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 
-fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working memcmp" >&5
+$as_echo_n "checking for working memcmp... " >&6; }
+if test "${ac_cv_func_memcmp_working+set}" = set; then :
+  $as_echo_n "(cached) " >&6
 else
-  $bailout
-fi
-
-done
-
-               check_lib_no_libs ccs ccs_connect
-               if test $NOTFOUND = 0; then
-                       { $as_echo "$as_me:$LINENO: result: no pkg for libccs, using -lccs" >&5
-$as_echo "no pkg for libccs, using -lccs" >&6; }
-                       CCS_LIBS="-lccs"
-                       HAVE_CCS=yes
-               fi
+  if test "$cross_compiling" = yes; then :
+  ac_cv_func_memcmp_working=no
 else
-       CCS_CFLAGS=$pkg_cv_CCS_CFLAGS
-       CCS_LIBS=$pkg_cv_CCS_LIBS
-        { $as_echo "$as_me:$LINENO: result: yes" >&5
-$as_echo "yes" >&6; }
-       HAVE_CCS=yes
-fi
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
 
-pkg_failed=no
-{ $as_echo "$as_me:$LINENO: checking for GULM" >&5
-$as_echo_n "checking for GULM... " >&6; }
+  /* Some versions of memcmp are not 8-bit clean.  */
+  char c0 = '\100', c1 = '\200', c2 = '\201';
+  if (memcmp(&c0, &c2, 1) >= 0 || memcmp(&c1, &c2, 1) >= 0)
+    return 1;
 
-if test -n "$GULM_CFLAGS"; then
-    pkg_cv_GULM_CFLAGS="$GULM_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libgulm\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libgulm") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_GULM_CFLAGS=`$PKG_CONFIG --cflags "libgulm" 2>/dev/null`
-else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
-fi
-if test -n "$GULM_LIBS"; then
-    pkg_cv_GULM_LIBS="$GULM_LIBS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libgulm\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libgulm") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_GULM_LIBS=`$PKG_CONFIG --libs "libgulm" 2>/dev/null`
+  /* The Next x86 OpenStep bug shows up only when comparing 16 bytes
+     or more and with at least one buffer not starting on a 4-byte boundary.
+     William Lewis provided this test program.   */
+  {
+    char foo[21];
+    char bar[21];
+    int i;
+    for (i = 0; i < 4; i++)
+      {
+       char *a = foo + i;
+       char *b = bar + i;
+       strcpy (a, "--------01111111");
+       strcpy (b, "--------10000000");
+       if (memcmp (a, b, 16) >= 0)
+         return 1;
+      }
+    return 0;
+  }
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_func_memcmp_working=yes
 else
-  pkg_failed=yes
+  ac_cv_func_memcmp_working=no
 fi
- else
-    pkg_failed=untried
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
 fi
 
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_memcmp_working" >&5
+$as_echo "$ac_cv_func_memcmp_working" >&6; }
+test $ac_cv_func_memcmp_working = no && case " $LIBOBJS " in
+  *" memcmp.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS memcmp.$ac_objext"
+ ;;
+esac
 
 
-if test $pkg_failed = yes; then
 
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
-else
-        _pkg_short_errors_supported=no
-fi
-        if test $_pkg_short_errors_supported = yes; then
-               GULM_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libgulm" 2>&1`
-        else
-               GULM_PKG_ERRORS=`$PKG_CONFIG --print-errors "libgulm" 2>&1`
-        fi
-       # Put the nasty error message in config.log where it belongs
-       echo "$GULM_PKG_ERRORS" >&5
 
-       { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-                NOTFOUND=0
 
-for ac_header in libgulm.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
+  for ac_header in $ac_header_list
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
 
-       ac_header_compiler=no
 fi
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
+done
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
 
-  ac_header_preproc=no
-fi
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
 
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  eval "$as_ac_Header=\$ac_header_preproc"
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 
-fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
+
+
+for ac_func in getpagesize
+do :
+  ac_fn_c_check_func "$LINENO" "getpagesize" "ac_cv_func_getpagesize"
+if test "x$ac_cv_func_getpagesize" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+#define HAVE_GETPAGESIZE 1
 _ACEOF
 
-else
-  $bailout
 fi
-
 done
 
-               check_lib_no_libs gulm lg_core_login
-               if test $NOTFOUND = 0; then
-                       { $as_echo "$as_me:$LINENO: result: no pkg for libgulm, using -lgulm" >&5
-$as_echo "no pkg for libgulm, using -lgulm" >&6; }
-                       GULM_LIBS="-lgulm"
-                       HAVE_GULM=yes
-               fi
-elif test $pkg_failed = untried; then
-       NOTFOUND=0
-
-for ac_header in libgulm.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working mmap" >&5
+$as_echo_n "checking for working mmap... " >&6; }
+if test "${ac_cv_func_mmap_fixed_mapped+set}" = set; then :
   $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  if test "$cross_compiling" = yes; then :
+  ac_cv_func_mmap_fixed_mapped=no
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 $ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+/* malloc might have been renamed as rpl_malloc. */
+#undef malloc
 
-       ac_header_compiler=no
-fi
+/* Thanks to Mike Haertel and Jim Avera for this test.
+   Here is a matrix of mmap possibilities:
+       mmap private not fixed
+       mmap private fixed at somewhere currently unmapped
+       mmap private fixed at somewhere already mapped
+       mmap shared not fixed
+       mmap shared fixed at somewhere currently unmapped
+       mmap shared fixed at somewhere already mapped
+   For private mappings, we should verify that changes cannot be read()
+   back from the file, nor mmap's back from the file at a different
+   address.  (There have been systems where private was not correctly
+   implemented like the infamous i386 svr4.0, and systems where the
+   VM page cache was not coherent with the file system buffer cache
+   like early versions of FreeBSD and possibly contemporary NetBSD.)
+   For shared mappings, we should conversely verify that changes get
+   propagated back to all the places they're supposed to be.
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
+   Grep wants private fixed already mapped.
+   The main things grep needs to know about mmap are:
+   * does it exist and is it safe to write into the mmap'd area
+   * how to use it (BSD variants)  */
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+#include <fcntl.h>
+#include <sys/mman.h>
 
-  ac_header_preproc=no
-fi
+#if !defined STDC_HEADERS && !defined HAVE_STDLIB_H
+char *malloc ();
+#endif
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
+/* This mess was copied from the GNU getpagesize.h.  */
+#ifndef HAVE_GETPAGESIZE
+# ifdef _SC_PAGESIZE
+#  define getpagesize() sysconf(_SC_PAGESIZE)
+# else /* no _SC_PAGESIZE */
+#  ifdef HAVE_SYS_PARAM_H
+#   include <sys/param.h>
+#   ifdef EXEC_PAGESIZE
+#    define getpagesize() EXEC_PAGESIZE
+#   else /* no EXEC_PAGESIZE */
+#    ifdef NBPG
+#     define getpagesize() NBPG * CLSIZE
+#     ifndef CLSIZE
+#      define CLSIZE 1
+#     endif /* no CLSIZE */
+#    else /* no NBPG */
+#     ifdef NBPC
+#      define getpagesize() NBPC
+#     else /* no NBPC */
+#      ifdef PAGESIZE
+#       define getpagesize() PAGESIZE
+#      endif /* PAGESIZE */
+#     endif /* no NBPC */
+#    endif /* no NBPG */
+#   endif /* no EXEC_PAGESIZE */
+#  else /* no HAVE_SYS_PARAM_H */
+#   define getpagesize() 8192  /* punt totally */
+#  endif /* no HAVE_SYS_PARAM_H */
+# endif /* no _SC_PAGESIZE */
 
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+#endif /* no HAVE_GETPAGESIZE */
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
+int
+main ()
+{
+  char *data, *data2, *data3;
+  const char *cdata2;
+  int i, pagesize;
+  int fd, fd2;
+
+  pagesize = getpagesize ();
+
+  /* First, make a file with some known garbage in it. */
+  data = (char *) malloc (pagesize);
+  if (!data)
+    return 1;
+  for (i = 0; i < pagesize; ++i)
+    *(data + i) = rand ();
+  umask (0);
+  fd = creat ("conftest.mmap", 0600);
+  if (fd < 0)
+    return 2;
+  if (write (fd, data, pagesize) != pagesize)
+    return 3;
+  close (fd);
+
+  /* Next, check that the tail of a page is zero-filled.  File must have
+     non-zero length, otherwise we risk SIGBUS for entire page.  */
+  fd2 = open ("conftest.txt", O_RDWR | O_CREAT | O_TRUNC, 0600);
+  if (fd2 < 0)
+    return 4;
+  cdata2 = "";
+  if (write (fd2, cdata2, 1) != 1)
+    return 5;
+  data2 = (char *) mmap (0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, 0L);
+  if (data2 == MAP_FAILED)
+    return 6;
+  for (i = 0; i < pagesize; ++i)
+    if (*(data2 + i))
+      return 7;
+  close (fd2);
+  if (munmap (data2, pagesize))
+    return 8;
+
+  /* Next, try to mmap the file at a fixed address which already has
+     something else allocated at it.  If we can, also make sure that
+     we see the same garbage.  */
+  fd = open ("conftest.mmap", O_RDWR);
+  if (fd < 0)
+    return 9;
+  if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE,
+                    MAP_PRIVATE | MAP_FIXED, fd, 0L))
+    return 10;
+  for (i = 0; i < pagesize; ++i)
+    if (*(data + i) != *(data2 + i))
+      return 11;
+
+  /* Finally, make sure that changes to the mapped area do not
+     percolate back to the file as seen by read().  (This is a bug on
+     some variants of i386 svr4.0.)  */
+  for (i = 0; i < pagesize; ++i)
+    *(data2 + i) = *(data2 + i) + 1;
+  data3 = (char *) malloc (pagesize);
+  if (!data3)
+    return 12;
+  if (read (fd, data3, pagesize) != pagesize)
+    return 13;
+  for (i = 0; i < pagesize; ++i)
+    if (*(data + i) != *(data3 + i))
+      return 14;
+  close (fd);
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_func_mmap_fixed_mapped=yes
 else
-  eval "$as_ac_Header=\$ac_header_preproc"
+  ac_cv_func_mmap_fixed_mapped=no
 fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_fixed_mapped" >&5
+$as_echo "$ac_cv_func_mmap_fixed_mapped" >&6; }
+if test $ac_cv_func_mmap_fixed_mapped = yes; then
+
+$as_echo "#define HAVE_MMAP 1" >>confdefs.h
 
 fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
+rm -f conftest.mmap conftest.txt
+
+for ac_header in stdlib.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default"
+if test "x$ac_cv_header_stdlib_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+#define HAVE_STDLIB_H 1
 _ACEOF
 
-else
-  $bailout
 fi
 
 done
 
-               check_lib_no_libs gulm lg_core_login
-               if test $NOTFOUND = 0; then
-                       { $as_echo "$as_me:$LINENO: result: no pkg for libgulm, using -lgulm" >&5
-$as_echo "no pkg for libgulm, using -lgulm" >&6; }
-                       GULM_LIBS="-lgulm"
-                       HAVE_GULM=yes
-               fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible realloc" >&5
+$as_echo_n "checking for GNU libc compatible realloc... " >&6; }
+if test "${ac_cv_func_realloc_0_nonnull+set}" = set; then :
+  $as_echo_n "(cached) " >&6
 else
-       GULM_CFLAGS=$pkg_cv_GULM_CFLAGS
-       GULM_LIBS=$pkg_cv_GULM_LIBS
-        { $as_echo "$as_me:$LINENO: result: yes" >&5
-$as_echo "yes" >&6; }
-       HAVE_GULM=yes
+  if test "$cross_compiling" = yes; then :
+  ac_cv_func_realloc_0_nonnull=no
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#if defined STDC_HEADERS || defined HAVE_STDLIB_H
+# include <stdlib.h>
+#else
+char *realloc ();
+#endif
+
+int
+main ()
+{
+return ! realloc (0, 0);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_func_realloc_0_nonnull=yes
+else
+  ac_cv_func_realloc_0_nonnull=no
 fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
 fi
 
-if test x$BUILDCMAN = xyes; then
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_realloc_0_nonnull" >&5
+$as_echo "$ac_cv_func_realloc_0_nonnull" >&6; }
+if test $ac_cv_func_realloc_0_nonnull = yes; then :
 
-pkg_failed=no
-{ $as_echo "$as_me:$LINENO: checking for CMAN" >&5
-$as_echo_n "checking for CMAN... " >&6; }
+$as_echo "#define HAVE_REALLOC 1" >>confdefs.h
 
-if test -n "$CMAN_CFLAGS"; then
-    pkg_cv_CMAN_CFLAGS="$CMAN_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libcman\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libcman") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_CMAN_CFLAGS=`$PKG_CONFIG --cflags "libcman" 2>/dev/null`
-else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
-fi
-if test -n "$CMAN_LIBS"; then
-    pkg_cv_CMAN_LIBS="$CMAN_LIBS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libcman\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libcman") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_CMAN_LIBS=`$PKG_CONFIG --libs "libcman" 2>/dev/null`
 else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
-fi
+  $as_echo "#define HAVE_REALLOC 0" >>confdefs.h
 
+   case " $LIBOBJS " in
+  *" realloc.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS realloc.$ac_objext"
+ ;;
+esac
 
 
-if test $pkg_failed = yes; then
+$as_echo "#define realloc rpl_realloc" >>confdefs.h
 
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
-else
-        _pkg_short_errors_supported=no
 fi
-        if test $_pkg_short_errors_supported = yes; then
-               CMAN_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libcman" 2>&1`
-        else
-               CMAN_PKG_ERRORS=`$PKG_CONFIG --print-errors "libcman" 2>&1`
-        fi
-       # Put the nasty error message in config.log where it belongs
-       echo "$CMAN_PKG_ERRORS" >&5
 
-       { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-                NOTFOUND=0
 
-for ac_header in libcman.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stat accepts an empty string" >&5
+$as_echo_n "checking whether stat accepts an empty string... " >&6; }
+if test "${ac_cv_func_stat_empty_string_bug+set}" = set; then :
   $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  if test "$cross_compiling" = yes; then :
+  ac_cv_func_stat_empty_string_bug=yes
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 $ac_includes_default
-#include <$ac_header>
+int
+main ()
+{
+struct stat sbuf;
+  return stat ("", &sbuf) == 0;
+  ;
+  return 0;
+}
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_func_stat_empty_string_bug=no
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  ac_cv_func_stat_empty_string_bug=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
 
-       ac_header_compiler=no
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_stat_empty_string_bug" >&5
+$as_echo "$ac_cv_func_stat_empty_string_bug" >&6; }
+if test $ac_cv_func_stat_empty_string_bug = yes; then
+  case " $LIBOBJS " in
+  *" stat.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS stat.$ac_objext"
+ ;;
+esac
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STAT_EMPTY_STRING_BUG 1
 _ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
 
-  ac_header_preproc=no
 fi
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working strtod" >&5
+$as_echo_n "checking for working strtod... " >&6; }
+if test "${ac_cv_func_strtod+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  ac_cv_func_strtod=no
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
 
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+$ac_includes_default
+#ifndef strtod
+double strtod ();
+#endif
+int
+main()
+{
+  {
+    /* Some versions of Linux strtod mis-parse strings with leading '+'.  */
+    char *string = " +69";
+    char *term;
+    double value;
+    value = strtod (string, &term);
+    if (value != 69 || term != (string + 4))
+      return 1;
+  }
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
+  {
+    /* Under Solaris 2.4, strtod returns the wrong value for the
+       terminating character under some conditions.  */
+    char *string = "NaN";
+    char *term;
+    strtod (string, &term);
+    if (term != string && *(term - 1) == 0)
+      return 1;
+  }
+  return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_func_strtod=yes
 else
-  eval "$as_ac_Header=\$ac_header_preproc"
+  ac_cv_func_strtod=no
 fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
 fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
 
-else
-  $bailout
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strtod" >&5
+$as_echo "$ac_cv_func_strtod" >&6; }
+if test $ac_cv_func_strtod = no; then
+  case " $LIBOBJS " in
+  *" strtod.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS strtod.$ac_objext"
+ ;;
+esac
 
-done
+ac_fn_c_check_func "$LINENO" "pow" "ac_cv_func_pow"
+if test "x$ac_cv_func_pow" = x""yes; then :
 
-               check_lib_no_libs cman cman_init
-               if test $NOTFOUND = 0; then
-                       { $as_echo "$as_me:$LINENO: result: no pkg for libcman, using -lcman" >&5
-$as_echo "no pkg for libcman, using -lcman" >&6; }
-                       CMAN_LIBS="-lcman"
-                       HAVE_CMAN=yes
-               fi
-elif test $pkg_failed = untried; then
-       NOTFOUND=0
+fi
 
-for ac_header in libcman.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+if test $ac_cv_func_pow = no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pow in -lm" >&5
+$as_echo_n "checking for pow in -lm... " >&6; }
+if test "${ac_cv_lib_m_pow+set}" = set; then :
   $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pow ();
+int
+main ()
+{
+return pow ();
+  ;
+  return 0;
+}
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_m_pow=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  ac_cv_lib_m_pow=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_pow" >&5
+$as_echo "$ac_cv_lib_m_pow" >&6; }
+if test "x$ac_cv_lib_m_pow" = x""yes; then :
+  POW_LIB=-lm
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot find library containing definition of pow" >&5
+$as_echo "$as_me: WARNING: cannot find library containing definition of pow" >&2;}
+fi
 
-       ac_header_compiler=no
 fi
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
+fi
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
+for ac_func in vprintf
+do :
+  ac_fn_c_check_func "$LINENO" "vprintf" "ac_cv_func_vprintf"
+if test "x$ac_cv_func_vprintf" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_VPRINTF 1
 _ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
 
-  ac_header_preproc=no
+ac_fn_c_check_func "$LINENO" "_doprnt" "ac_cv_func__doprnt"
+if test "x$ac_cv_func__doprnt" = x""yes; then :
+
+$as_echo "#define HAVE_DOPRNT 1" >>confdefs.h
+
 fi
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
+fi
+done
 
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
+
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use static linking" >&5
+$as_echo_n "checking whether to use static linking... " >&6; }
+# Check whether --enable-static_link was given.
+if test "${enable_static_link+set}" = set; then :
+  enableval=$enable_static_link; STATIC_LINK=$enableval
 else
-  eval "$as_ac_Header=\$ac_header_preproc"
+  STATIC_LINK=no
 fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $STATIC_LINK" >&5
+$as_echo "$STATIC_LINK" >&6; }
+
+################################################################################
+
+
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking file owner" >&5
+$as_echo_n "checking file owner... " >&6; }
+
+# Check whether --with-user was given.
+if test "${with_user+set}" = set; then :
+  withval=$with_user; OWNER=$withval
 fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
 
-else
-  $bailout
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $OWNER" >&5
+$as_echo "$OWNER" >&6; }
+
+if test x$OWNER != x; then
+       INSTALL="$INSTALL -o $OWNER"
 fi
 
-done
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking group owner" >&5
+$as_echo_n "checking group owner... " >&6; }
 
-               check_lib_no_libs cman cman_init
-               if test $NOTFOUND = 0; then
-                       { $as_echo "$as_me:$LINENO: result: no pkg for libcman, using -lcman" >&5
-$as_echo "no pkg for libcman, using -lcman" >&6; }
-                       CMAN_LIBS="-lcman"
-                       HAVE_CMAN=yes
-               fi
-else
-       CMAN_CFLAGS=$pkg_cv_CMAN_CFLAGS
-       CMAN_LIBS=$pkg_cv_CMAN_LIBS
-        { $as_echo "$as_me:$LINENO: result: yes" >&5
-$as_echo "yes" >&6; }
-       HAVE_CMAN=yes
+# Check whether --with-group was given.
+if test "${with_group+set}" = set; then :
+  withval=$with_group; GROUP=$withval
 fi
-       CHECKCONFDB=yes
-       CHECKDLM=yes
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $GROUP" >&5
+$as_echo "$GROUP" >&6; }
+
+if test x$GROUP != x; then
+       INSTALL="$INSTALL -g $GROUP"
 fi
 
-if test x$BUILDCOROSYNC = xyes || \
-   test x$BUILDOPENAIS = xyes; then
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking device node uid" >&5
+$as_echo_n "checking device node uid... " >&6; }
 
-pkg_failed=no
-{ $as_echo "$as_me:$LINENO: checking for COROSYNC" >&5
-$as_echo_n "checking for COROSYNC... " >&6; }
 
-if test -n "$COROSYNC_CFLAGS"; then
-    pkg_cv_COROSYNC_CFLAGS="$COROSYNC_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"corosync\"") >&5
-  ($PKG_CONFIG --exists --print-errors "corosync") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_COROSYNC_CFLAGS=`$PKG_CONFIG --cflags "corosync" 2>/dev/null`
+# Check whether --with-device-uid was given.
+if test "${with_device_uid+set}" = set; then :
+  withval=$with_device_uid; DM_DEVICE_UID=$withval
 else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
+  DM_DEVICE_UID=0
 fi
-if test -n "$COROSYNC_LIBS"; then
-    pkg_cv_COROSYNC_LIBS="$COROSYNC_LIBS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"corosync\"") >&5
-  ($PKG_CONFIG --exists --print-errors "corosync") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_COROSYNC_LIBS=`$PKG_CONFIG --libs "corosync" 2>/dev/null`
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DM_DEVICE_UID" >&5
+$as_echo "$DM_DEVICE_UID" >&6; }
+
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking device node gid" >&5
+$as_echo_n "checking device node gid... " >&6; }
+
+
+# Check whether --with-device-gid was given.
+if test "${with_device_gid+set}" = set; then :
+  withval=$with_device_gid; DM_DEVICE_GID=$withval
 else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
+  DM_DEVICE_GID=0
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DM_DEVICE_GID" >&5
+$as_echo "$DM_DEVICE_GID" >&6; }
 
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking device node mode" >&5
+$as_echo_n "checking device node mode... " >&6; }
 
-if test $pkg_failed = yes; then
 
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
+# Check whether --with-device-mode was given.
+if test "${with_device_mode+set}" = set; then :
+  withval=$with_device_mode; DM_DEVICE_MODE=$withval
 else
-        _pkg_short_errors_supported=no
+  DM_DEVICE_MODE=0600
 fi
-        if test $_pkg_short_errors_supported = yes; then
-               COROSYNC_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "corosync" 2>&1`
-        else
-               COROSYNC_PKG_ERRORS=`$PKG_CONFIG --print-errors "corosync" 2>&1`
-        fi
-       # Put the nasty error message in config.log where it belongs
-       echo "$COROSYNC_PKG_ERRORS" >&5
 
-       { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-                $bailout
-elif test $pkg_failed = untried; then
-       $bailout
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DM_DEVICE_MODE" >&5
+$as_echo "$DM_DEVICE_MODE" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking when to create device nodes" >&5
+$as_echo_n "checking when to create device nodes... " >&6; }
+
+# Check whether --with-device-nodes-on was given.
+if test "${with_device_nodes_on+set}" = set; then :
+  withval=$with_device_nodes_on; ADD_NODE=$withval
 else
-       COROSYNC_CFLAGS=$pkg_cv_COROSYNC_CFLAGS
-       COROSYNC_LIBS=$pkg_cv_COROSYNC_LIBS
-        { $as_echo "$as_me:$LINENO: result: yes" >&5
-$as_echo "yes" >&6; }
-       HAVE_COROSYNC=yes
-fi
-       CHECKCONFDB=yes
+  ADD_NODE=resume
 fi
 
-if test x$BUILDCOROSYNC = xyes; then
+case "$ADD_NODE" in
+ resume) add_on=DM_ADD_NODE_ON_RESUME;;
+ create) add_on=DM_ADD_NODE_ON_CREATE;;
+ *) as_fn_error $? "--with-device-nodes-on parameter invalid" "$LINENO" 5;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: on $ADD_NODE" >&5
+$as_echo "on $ADD_NODE" >&6; }
 
-pkg_failed=no
-{ $as_echo "$as_me:$LINENO: checking for QUORUM" >&5
-$as_echo_n "checking for QUORUM... " >&6; }
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_DM_ADD_NODE $add_on
+_ACEOF
 
-if test -n "$QUORUM_CFLAGS"; then
-    pkg_cv_QUORUM_CFLAGS="$QUORUM_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libquorum\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libquorum") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_QUORUM_CFLAGS=`$PKG_CONFIG --cflags "libquorum" 2>/dev/null`
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking default name mangling" >&5
+$as_echo_n "checking default name mangling... " >&6; }
+
+# Check whether --with-default-name-mangling was given.
+if test "${with_default_name_mangling+set}" = set; then :
+  withval=$with_default_name_mangling; MANGLING=$withval
 else
-  pkg_failed=yes
+  MANGLING=auto
 fi
- else
-    pkg_failed=untried
-fi
-if test -n "$QUORUM_LIBS"; then
-    pkg_cv_QUORUM_LIBS="$QUORUM_LIBS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libquorum\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libquorum") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_QUORUM_LIBS=`$PKG_CONFIG --libs "libquorum" 2>/dev/null`
+
+case "$MANGLING" in
+ auto) mangling=DM_STRING_MANGLING_AUTO;;
+ disabled) mangling=DM_STRING_MANGLING_NONE;;
+ hex) mangling=DM_STRING_MANGLING_HEX;;
+ *) as_fn_error $? "--with-default-name-mangling parameter invalid" "$LINENO" 5;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANGLING" >&5
+$as_echo "$MANGLING" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_DM_NAME_MANGLING $mangling
+_ACEOF
+
+
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable lvm1 fallback" >&5
+$as_echo_n "checking whether to enable lvm1 fallback... " >&6; }
+# Check whether --enable-lvm1_fallback was given.
+if test "${enable_lvm1_fallback+set}" = set; then :
+  enableval=$enable_lvm1_fallback; LVM1_FALLBACK=$enableval
 else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
+  LVM1_FALLBACK=no
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LVM1_FALLBACK" >&5
+$as_echo "$LVM1_FALLBACK" >&6; }
 
+if test x$LVM1_FALLBACK = xyes; then
 
-if test $pkg_failed = yes; then
+$as_echo "#define LVM1_FALLBACK 1" >>confdefs.h
 
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
-else
-        _pkg_short_errors_supported=no
 fi
-        if test $_pkg_short_errors_supported = yes; then
-               QUORUM_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libquorum" 2>&1`
-        else
-               QUORUM_PKG_ERRORS=`$PKG_CONFIG --print-errors "libquorum" 2>&1`
-        fi
-       # Put the nasty error message in config.log where it belongs
-       echo "$QUORUM_PKG_ERRORS" >&5
 
-       { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-                $bailout
-elif test $pkg_failed = untried; then
-       $bailout
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include support for lvm1 metadata" >&5
+$as_echo_n "checking whether to include support for lvm1 metadata... " >&6; }
+
+# Check whether --with-lvm1 was given.
+if test "${with_lvm1+set}" = set; then :
+  withval=$with_lvm1; LVM1=$withval
 else
-       QUORUM_CFLAGS=$pkg_cv_QUORUM_CFLAGS
-       QUORUM_LIBS=$pkg_cv_QUORUM_LIBS
-        { $as_echo "$as_me:$LINENO: result: yes" >&5
-$as_echo "yes" >&6; }
-       HAVE_QUORUM=yes
-fi
-       CHECKCPG=yes
-       CHECKDLM=yes
+  LVM1=internal
 fi
 
-if test x$BUILDOPENAIS = xyes; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LVM1" >&5
+$as_echo "$LVM1" >&6; }
 
-pkg_failed=no
-{ $as_echo "$as_me:$LINENO: checking for SALCK" >&5
-$as_echo_n "checking for SALCK... " >&6; }
+if [ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ];
+ then  as_fn_error $? "--with-lvm1 parameter invalid
+" "$LINENO" 5
+fi;
+
+if test x$LVM1 = xinternal; then
+
+$as_echo "#define LVM1_INTERNAL 1" >>confdefs.h
 
-if test -n "$SALCK_CFLAGS"; then
-    pkg_cv_SALCK_CFLAGS="$SALCK_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libSaLck\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libSaLck") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_SALCK_CFLAGS=`$PKG_CONFIG --cflags "libSaLck" 2>/dev/null`
-else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
 fi
-if test -n "$SALCK_LIBS"; then
-    pkg_cv_SALCK_LIBS="$SALCK_LIBS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libSaLck\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libSaLck") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_SALCK_LIBS=`$PKG_CONFIG --libs "libSaLck" 2>/dev/null`
+
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include support for GFS pool metadata" >&5
+$as_echo_n "checking whether to include support for GFS pool metadata... " >&6; }
+
+# Check whether --with-pool was given.
+if test "${with_pool+set}" = set; then :
+  withval=$with_pool; POOL=$withval
 else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
+  POOL=internal
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $POOL" >&5
+$as_echo "$POOL" >&6; }
 
+if [ "x$POOL" != xnone -a "x$POOL" != xinternal -a "x$POOL" != xshared ];
+ then  as_fn_error $? "--with-pool parameter invalid
+" "$LINENO" 5
+fi;
 
-if test $pkg_failed = yes; then
+if test x$POOL = xinternal; then
 
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
-else
-        _pkg_short_errors_supported=no
-fi
-        if test $_pkg_short_errors_supported = yes; then
-               SALCK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libSaLck" 2>&1`
-        else
-               SALCK_PKG_ERRORS=`$PKG_CONFIG --print-errors "libSaLck" 2>&1`
-        fi
-       # Put the nasty error message in config.log where it belongs
-       echo "$SALCK_PKG_ERRORS" >&5
+$as_echo "#define POOL_INTERNAL 1" >>confdefs.h
 
-       { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-                $bailout
-elif test $pkg_failed = untried; then
-       $bailout
-else
-       SALCK_CFLAGS=$pkg_cv_SALCK_CFLAGS
-       SALCK_LIBS=$pkg_cv_SALCK_LIBS
-        { $as_echo "$as_me:$LINENO: result: yes" >&5
-$as_echo "yes" >&6; }
-       HAVE_SALCK=yes
 fi
-       CHECKCPG=yes
+
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include support for cluster locking" >&5
+$as_echo_n "checking whether to include support for cluster locking... " >&6; }
+
+# Check whether --with-cluster was given.
+if test "${with_cluster+set}" = set; then :
+  withval=$with_cluster; CLUSTER=$withval
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CLUSTER" >&5
+$as_echo "$CLUSTER" >&6; }
 
+if [ "x$CLUSTER" != xnone -a "x$CLUSTER" != xinternal -a "x$CLUSTER" != xshared ];
+ then  as_fn_error $? "--with-cluster parameter invalid
+" "$LINENO" 5
+fi;
 
-if test x$CHECKCONFDB = xyes; then
+if test x$CLUSTER = xinternal; then
 
-pkg_failed=no
-{ $as_echo "$as_me:$LINENO: checking for CONFDB" >&5
-$as_echo_n "checking for CONFDB... " >&6; }
+$as_echo "#define CLUSTER_LOCKING_INTERNAL 1" >>confdefs.h
 
-if test -n "$CONFDB_CFLAGS"; then
-    pkg_cv_CONFDB_CFLAGS="$CONFDB_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libconfdb\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libconfdb") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_CONFDB_CFLAGS=`$PKG_CONFIG --cflags "libconfdb" 2>/dev/null`
-else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
 fi
-if test -n "$CONFDB_LIBS"; then
-    pkg_cv_CONFDB_LIBS="$CONFDB_LIBS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libconfdb\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libconfdb") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_CONFDB_LIBS=`$PKG_CONFIG --libs "libconfdb" 2>/dev/null`
+
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include snapshots" >&5
+$as_echo_n "checking whether to include snapshots... " >&6; }
+
+# Check whether --with-snapshots was given.
+if test "${with_snapshots+set}" = set; then :
+  withval=$with_snapshots; SNAPSHOTS=$withval
 else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
+  SNAPSHOTS=internal
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $SNAPSHOTS" >&5
+$as_echo "$SNAPSHOTS" >&6; }
 
+if [ "x$SNAPSHOTS" != xnone -a "x$SNAPSHOTS" != xinternal -a "x$SNAPSHOTS" != xshared ];
+ then  as_fn_error $? "--with-snapshots parameter invalid
+" "$LINENO" 5
+fi;
 
-if test $pkg_failed = yes; then
+if test x$SNAPSHOTS = xinternal; then
+
+$as_echo "#define SNAPSHOT_INTERNAL 1" >>confdefs.h
 
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
-else
-        _pkg_short_errors_supported=no
 fi
-        if test $_pkg_short_errors_supported = yes; then
-               CONFDB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libconfdb" 2>&1`
-        else
-               CONFDB_PKG_ERRORS=`$PKG_CONFIG --print-errors "libconfdb" 2>&1`
-        fi
-       # Put the nasty error message in config.log where it belongs
-       echo "$CONFDB_PKG_ERRORS" >&5
 
-       { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-                HAVE_CONFDB=no
-elif test $pkg_failed = untried; then
-       HAVE_CONFDB=no
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include mirrors" >&5
+$as_echo_n "checking whether to include mirrors... " >&6; }
+
+# Check whether --with-mirrors was given.
+if test "${with_mirrors+set}" = set; then :
+  withval=$with_mirrors; MIRRORS=$withval
 else
-       CONFDB_CFLAGS=$pkg_cv_CONFDB_CFLAGS
-       CONFDB_LIBS=$pkg_cv_CONFDB_LIBS
-        { $as_echo "$as_me:$LINENO: result: yes" >&5
-$as_echo "yes" >&6; }
-       HAVE_CONFDB=yes
+  MIRRORS=internal
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MIRRORS" >&5
+$as_echo "$MIRRORS" >&6; }
 
-for ac_header in corosync/confdb.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+if [ "x$MIRRORS" != xnone -a "x$MIRRORS" != xinternal -a "x$MIRRORS" != xshared ];
+ then  as_fn_error $? "--with-mirrors parameter invalid
+" "$LINENO" 5
+fi;
+
+if test x$MIRRORS = xinternal; then
+
+$as_echo "#define MIRRORED_INTERNAL 1" >>confdefs.h
 
-       ac_header_compiler=no
 fi
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include raid" >&5
+$as_echo_n "checking whether to include raid... " >&6; }
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
+# Check whether --with-raid was given.
+if test "${with_raid+set}" = set; then :
+  withval=$with_raid; RAID=$withval
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  ac_header_preproc=no
+  RAID=internal
 fi
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $RAID" >&5
+$as_echo "$RAID" >&6; }
 
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+if [ "x$RAID" != xnone -a "x$RAID" != xinternal -a "x$RAID" != xshared ];
+ then  as_fn_error $? "--with-raid parameter invalid
+" "$LINENO" 5
+fi;
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  eval "$as_ac_Header=\$ac_header_preproc"
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+if test x$RAID = xinternal; then
+
+$as_echo "#define RAID_INTERNAL 1" >>confdefs.h
 
 fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
- HAVE_CONFDB_H=yes
+
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include replicators" >&5
+$as_echo_n "checking whether to include replicators... " >&6; }
+
+# Check whether --with-replicators was given.
+if test "${with_replicators+set}" = set; then :
+  withval=$with_replicators; REPLICATORS=$withval
 else
-  HAVE_CONFDB_H=no
+  REPLICATORS=none
 fi
 
-done
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $REPLICATORS" >&5
+$as_echo "$REPLICATORS" >&6; }
 
+case "$REPLICATORS" in
+  none|shared) ;;
+  internal)
+$as_echo "#define REPLICATOR_INTERNAL 1" >>confdefs.h
+ ;;
+  *) as_fn_error $? "--with-replicators parameter invalid ($REPLICATORS)" "$LINENO" 5 ;;
+esac
 
-       if test x$HAVE_CONFDB != xyes && \
-          test x$HAVE_CONFDB_H = xyes; then
-               check_lib_no_libs confdb confdb_initialize
-               { $as_echo "$as_me:$LINENO: result: no pkg for confdb, using -lconfdb" >&5
-$as_echo "no pkg for confdb, using -lconfdb" >&6; }
-               CONFDB_LIBS="-lconfdb"
-               HAVE_CONFDB=yes
-       fi
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include thin provisioning" >&5
+$as_echo_n "checking whether to include thin provisioning... " >&6; }
 
-       if test x$BUILDCOROSYNC = xyes && \
-          test x$HAVE_CONFDB != xyes &&
-          test x$CLVMD != xall; then
-               { { $as_echo "$as_me:$LINENO: error: bailing out... confdb library is required" >&5
-$as_echo "$as_me: error: bailing out... confdb library is required" >&2;}
-   { (exit 1); exit 1; }; }
-       fi
+# Check whether --with-thin was given.
+if test "${with_thin+set}" = set; then :
+  withval=$with_thin; THIN=$withval
+else
+  THIN=none
 fi
 
-if test x$CHECKCPG = xyes; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $THIN" >&5
+$as_echo "$THIN" >&6; }
 
-pkg_failed=no
-{ $as_echo "$as_me:$LINENO: checking for CPG" >&5
-$as_echo_n "checking for CPG... " >&6; }
+case "$THIN" in
+  none|shared) ;;
+  internal)
+$as_echo "#define THIN_INTERNAL 1" >>confdefs.h
+ ;;
+  *) as_fn_error $? "--with-thin parameter invalid ($THIN)" "$LINENO" 5 ;;
+esac
 
-if test -n "$CPG_CFLAGS"; then
-    pkg_cv_CPG_CFLAGS="$CPG_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libcpg\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libcpg") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_CPG_CFLAGS=`$PKG_CONFIG --cflags "libcpg" 2>/dev/null`
+case "$THIN" in
+  internal|shared)
+
+# Check whether --with-thin-check was given.
+if test "${with_thin_check+set}" = set; then :
+  withval=$with_thin_check; THIN_CHECK_CMD=$withval
 else
-  pkg_failed=yes
+  THIN_CHECK_CMD="autodetect"
 fi
- else
-    pkg_failed=untried
-fi
-if test -n "$CPG_LIBS"; then
-    pkg_cv_CPG_LIBS="$CPG_LIBS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libcpg\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libcpg") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_CPG_LIBS=`$PKG_CONFIG --libs "libcpg" 2>/dev/null`
+
+       # Empty means a config way to ignore thin checking
+       if test "$THIN_CHECK_CMD" = "autodetect"; then
+               # Extract the first word of "thin_check", so it can be a program name with args.
+set dummy thin_check; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_path_THIN_CHECK_CMD+set}" = set; then :
+  $as_echo_n "(cached) " >&6
 else
-  pkg_failed=yes
+  case $THIN_CHECK_CMD in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_THIN_CHECK_CMD="$THIN_CHECK_CMD" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_THIN_CHECK_CMD="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
 fi
- else
-    pkg_failed=untried
+THIN_CHECK_CMD=$ac_cv_path_THIN_CHECK_CMD
+if test -n "$THIN_CHECK_CMD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $THIN_CHECK_CMD" >&5
+$as_echo "$THIN_CHECK_CMD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
 
+               test -z "$THIN_CHECK_CMD" && as_fn_error $? "thin_check not found in path $PATH" "$LINENO" 5
+       fi
+       ;;
+esac
+
+
+cat >>confdefs.h <<_ACEOF
+#define THIN_CHECK_CMD "$THIN_CHECK_CMD"
+_ACEOF
+
 
-if test $pkg_failed = yes; then
 
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable readline" >&5
+$as_echo_n "checking whether to enable readline... " >&6; }
+# Check whether --enable-readline was given.
+if test "${enable_readline+set}" = set; then :
+  enableval=$enable_readline; READLINE=$enableval
 else
-        _pkg_short_errors_supported=no
+  READLINE=maybe
 fi
-        if test $_pkg_short_errors_supported = yes; then
-               CPG_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libcpg" 2>&1`
-        else
-               CPG_PKG_ERRORS=`$PKG_CONFIG --print-errors "libcpg" 2>&1`
-        fi
-       # Put the nasty error message in config.log where it belongs
-       echo "$CPG_PKG_ERRORS" >&5
 
-       { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-                $bailout
-elif test $pkg_failed = untried; then
-       $bailout
-else
-       CPG_CFLAGS=$pkg_cv_CPG_CFLAGS
-       CPG_LIBS=$pkg_cv_CPG_LIBS
-        { $as_echo "$as_me:$LINENO: result: yes" >&5
-$as_echo "yes" >&6; }
-       HAVE_CPG=yes
-fi
-fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $READLINE" >&5
+$as_echo "$READLINE" >&6; }
 
-if test x$CHECKDLM = xyes; then
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable realtime support" >&5
+$as_echo_n "checking whether to enable realtime support... " >&6; }
+# Check whether --enable-realtime was given.
+if test "${enable_realtime+set}" = set; then :
+  enableval=$enable_realtime; REALTIME=$enableval
+fi
 
-pkg_failed=no
-{ $as_echo "$as_me:$LINENO: checking for DLM" >&5
-$as_echo_n "checking for DLM... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $REALTIME" >&5
+$as_echo "$REALTIME" >&6; }
 
-if test -n "$DLM_CFLAGS"; then
-    pkg_cv_DLM_CFLAGS="$DLM_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libdlm\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libdlm") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_DLM_CFLAGS=`$PKG_CONFIG --cflags "libdlm" 2>/dev/null`
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable OCF resource agents" >&5
+$as_echo_n "checking whether to enable OCF resource agents... " >&6; }
+# Check whether --enable-ocf was given.
+if test "${enable_ocf+set}" = set; then :
+  enableval=$enable_ocf; OCF=$enableval
 else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
+  OCF=no
 fi
-if test -n "$DLM_LIBS"; then
-    pkg_cv_DLM_LIBS="$DLM_LIBS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libdlm\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libdlm") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_DLM_LIBS=`$PKG_CONFIG --libs "libdlm" 2>/dev/null`
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $OCF" >&5
+$as_echo "$OCF" >&6; }
+
+# Check whether --with-ocfdir was given.
+if test "${with_ocfdir+set}" = set; then :
+  withval=$with_ocfdir; OCFDIR=$withval
 else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
+  OCFDIR='${prefix}/lib/ocf/resource.d/lvm2'
 fi
 
 
+################################################################################
+pkg_config_init() {
 
-if test $pkg_failed = yes; then
 
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
-else
-        _pkg_short_errors_supported=no
-fi
-        if test $_pkg_short_errors_supported = yes; then
-               DLM_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libdlm" 2>&1`
-        else
-               DLM_PKG_ERRORS=`$PKG_CONFIG --print-errors "libdlm" 2>&1`
-        fi
-       # Put the nasty error message in config.log where it belongs
-       echo "$DLM_PKG_ERRORS" >&5
 
-       { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-                NOTFOUND=0
 
-for ac_header in libdlm.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+       if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_path_PKG_CONFIG+set}" = set; then :
   $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_header_compiler=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+  ac_pt_PKG_CONFIG=$PKG_CONFIG
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then :
+  $as_echo_n "(cached) " >&6
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  case $ac_pt_PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
-  ac_header_preproc=no
+  ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
-
-    ;;
+  if test "x$ac_pt_PKG_CONFIG" = x; then
+    PKG_CONFIG=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
 esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
+    PKG_CONFIG=$ac_pt_PKG_CONFIG
+  fi
 else
-  eval "$as_ac_Header=\$ac_header_preproc"
+  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
 fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 
 fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-else
-  $bailout
+if test -n "$PKG_CONFIG"; then
+       _pkg_min_version=0.9.0
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+       if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+       else
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+               PKG_CONFIG=""
+       fi
 fi
 
-done
-
-               check_lib_no_libs dlm dlm_lock -lpthread
-               if test $NOTFOUND = 0; then
-                       { $as_echo "$as_me:$LINENO: result: no pkg for libdlm, using -ldlm" >&5
-$as_echo "no pkg for libdlm, using -ldlm" >&6; }
-                       DLM_LIBS="-ldlm -lpthread"
-                       HAVE_DLM=yes
-               fi
-elif test $pkg_failed = untried; then
-       NOTFOUND=0
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PKGCONFIGINIT" >&5
+$as_echo_n "checking for PKGCONFIGINIT... " >&6; }
 
-for ac_header in libdlm.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+if test -n "$PKGCONFIGINIT_CFLAGS"; then
+    pkg_cv_PKGCONFIGINIT_CFLAGS="$PKGCONFIGINIT_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"pkgconfiginit\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "pkgconfiginit") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_PKGCONFIGINIT_CFLAGS=`$PKG_CONFIG --cflags "pkgconfiginit" 2>/dev/null`
 else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$PKGCONFIGINIT_LIBS"; then
+    pkg_cv_PKGCONFIGINIT_LIBS="$PKGCONFIGINIT_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"pkgconfiginit\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "pkgconfiginit") 2>&5
   ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_PKGCONFIGINIT_LIBS=`$PKG_CONFIG --libs "pkgconfiginit" 2>/dev/null`
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_header_compiler=no
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
 fi
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
+
+if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+               PKGCONFIGINIT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "pkgconfiginit" 2>&1`
+        else
+               PKGCONFIGINIT_PKG_ERRORS=`$PKG_CONFIG --print-errors "pkgconfiginit" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$PKGCONFIGINIT_PKG_ERRORS" >&5
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: pkg-config initialized" >&5
+$as_echo "pkg-config initialized" >&6; }
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: pkg-config initialized" >&5
+$as_echo "pkg-config initialized" >&6; }
+else
+       PKGCONFIGINIT_CFLAGS=$pkg_cv_PKGCONFIGINIT_CFLAGS
+       PKGCONFIGINIT_LIBS=$pkg_cv_PKGCONFIGINIT_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
 
-  ac_header_preproc=no
 fi
+       PKGCONFIG_INIT=1
+}
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
+################################################################################
 
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
+# Check whether --with-default-pid-dir was given.
+if test "${with_default_pid_dir+set}" = set; then :
+  withval=$with_default_pid_dir; DEFAULT_PID_DIR="$withval"
 else
-  eval "$as_ac_Header=\$ac_header_preproc"
+  DEFAULT_PID_DIR="/var/run"
 fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 
-fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_PID_DIR "$DEFAULT_PID_DIR"
 _ACEOF
 
-else
-  $bailout
-fi
 
-done
 
-               check_lib_no_libs dlm dlm_lock -lpthread
-               if test $NOTFOUND = 0; then
-                       { $as_echo "$as_me:$LINENO: result: no pkg for libdlm, using -ldlm" >&5
-$as_echo "no pkg for libdlm, using -ldlm" >&6; }
-                       DLM_LIBS="-ldlm -lpthread"
-                       HAVE_DLM=yes
-               fi
+
+# Check whether --with-default-dm-run-dir was given.
+if test "${with_default_dm_run_dir+set}" = set; then :
+  withval=$with_default_dm_run_dir; DEFAULT_DM_RUN_DIR="$withval"
 else
-       DLM_CFLAGS=$pkg_cv_DLM_CFLAGS
-       DLM_LIBS=$pkg_cv_DLM_LIBS
-        { $as_echo "$as_me:$LINENO: result: yes" >&5
-$as_echo "yes" >&6; }
-       HAVE_DLM=yes
-fi
+  DEFAULT_DM_RUN_DIR="/var/run"
 fi
 
-if test x$CLVMD = xall; then
-       CLVMD=none
-       CLVMD_CMANAGERS=""
-       CLVMD_NEEDS_QDISKD=no
-       if test x$HAVE_CCS = xyes && \
-          test x$HAVE_GULM = xyes; then
-               { $as_echo "$as_me:$LINENO: result: Enabling clvmd gulm cluster manager" >&5
-$as_echo "Enabling clvmd gulm cluster manager" >&6; }
-               CLVMD="$CLVMD,gulm"
-               CLVMD_CMANAGERS="$CLVMD_CMANAGERS lock_gulmd"
-               CLVMD_NEEDS_QDISKD=yes
-       fi
-       if test x$HAVE_CMAN = xyes && \
-          test x$HAVE_DLM = xyes; then
-               { $as_echo "$as_me:$LINENO: result: Enabling clvmd cman cluster manager" >&5
-$as_echo "Enabling clvmd cman cluster manager" >&6; }
-               CLVMD="$CLVMD,cman"
-               CLVMD_CMANAGERS="$CLVMD_CMANAGERS cman"
-               CLVMD_NEEDS_QDISKD=yes
-       fi
-       if test x$HAVE_COROSYNC = xyes && \
-          test x$HAVE_QUORUM = xyes && \
-          test x$HAVE_CPG = xyes && \
-          test x$HAVE_DLM = xyes && \
-          test x$HAVE_CONFDB = xyes; then
-               { $as_echo "$as_me:$LINENO: result: Enabling clvmd corosync cluster manager" >&5
-$as_echo "Enabling clvmd corosync cluster manager" >&6; }
-               CLVMD="$CLVMD,corosync"
-               CLVMD_CMANAGERS="$CLVMD_CMANAGERS corosync"
-       fi
-       if test x$HAVE_COROSYNC = xyes && \
-          test x$HAVE_CPG = xyes && \
-          test x$HAVE_SALCK = xyes; then
-               { $as_echo "$as_me:$LINENO: result: Enabling clvmd openais cluster manager" >&5
-$as_echo "Enabling clvmd openais cluster manager" >&6; }
-               CLVMD="$CLVMD,openais"
-               CLVMD_CMANAGERS="$CLVMD_CMANAGERS openais"
-       fi
-       if test x$CLVMD_NEEDS_QDISKD != xno; then
-               CLVMD_CMANAGERS="$CLVMD_CMANAGERS qdiskd"
-       fi
-       if test x$CLVMD = xnone; then
-               { $as_echo "$as_me:$LINENO: result: Disabling clvmd build. No cluster manager detected." >&5
-$as_echo "Disabling clvmd build. No cluster manager detected." >&6; }
-       fi
-fi
 
-################################################################################
-if test "x$CLVMD" != xnone; then
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_DM_RUN_DIR "$DEFAULT_DM_RUN_DIR"
+_ACEOF
 
-# Check whether --with-clvmd-pidfile was given.
-if test "${with_clvmd_pidfile+set}" = set; then
-  withval=$with_clvmd_pidfile; CLVMD_PIDFILE=$withval
+
+
+
+# Check whether --with-default-run-dir was given.
+if test "${with_default_run_dir+set}" = set; then :
+  withval=$with_default_run_dir; DEFAULT_RUN_DIR="$withval"
 else
-  CLVMD_PIDFILE="/var/run/clvmd.pid"
+  DEFAULT_RUN_DIR="/var/run/lvm"
 fi
 
 
 cat >>confdefs.h <<_ACEOF
-#define CLVMD_PIDFILE "$CLVMD_PIDFILE"
+#define DEFAULT_RUN_DIR "$DEFAULT_RUN_DIR"
 _ACEOF
 
-fi
 
 ################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to build cluster mirror log daemon" >&5
-$as_echo_n "checking whether to build cluster mirror log daemon... " >&6; }
-# Check whether --enable-cmirrord was given.
-if test "${enable_cmirrord+set}" = set; then
-  enableval=$enable_cmirrord; CMIRRORD=$enableval
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build cluster LVM daemon" >&5
+$as_echo_n "checking whether to build cluster LVM daemon... " >&6; }
+
+# Check whether --with-clvmd was given.
+if test "${with_clvmd+set}" = set; then :
+  withval=$with_clvmd; CLVMD=$withval
 else
-  CMIRRORD=no
+  CLVMD=none
 fi
 
-{ $as_echo "$as_me:$LINENO: result: $CMIRRORD" >&5
-$as_echo "$CMIRRORD" >&6; }
-
-BUILD_CMIRRORD=$CMIRRORD
-
-################################################################################
-if test "x$BUILD_CMIRRORD" = xyes; then
+if test x$CLVMD = xyes; then
+       CLVMD=all
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CLVMD" >&5
+$as_echo "$CLVMD" >&6; }
 
-# Check whether --with-cmirrord-pidfile was given.
-if test "${with_cmirrord_pidfile+set}" = set; then
-  withval=$with_cmirrord_pidfile; CMIRRORD_PIDFILE=$withval
-else
-  CMIRRORD_PIDFILE="/var/run/cmirrord.pid"
+if  test x$CLVMD != xnone && test x$CLUSTER = xnone; then
+       CLUSTER=internal
 fi
 
+if test x$CLVMD != xnone && test x$PKGCONFIG_INIT != x1; then
+       pkg_config_init
+fi
 
-cat >>confdefs.h <<_ACEOF
-#define CMIRRORD_PIDFILE "$CMIRRORD_PIDFILE"
-_ACEOF
+CLVMD_CMANAGERS=""
+CLVMD_NEEDS_QDISKD=no
 
+if [ `expr x"$CLVMD" : '.*gulm.*'` != 0 ]; then
+       as_fn_error $? "Since version 2.02.87 GULM locking is no longer supported." "$LINENO" 5;
+fi
+if [ `expr x"$CLVMD" : '.*cman.*'` != 0 ]; then
+       BUILDCMAN=yes
+       CLVMD_CMANAGERS="$CLVMD_CMANAGERS cman"
+       CLVMD_NEEDS_QDISKD=yes
+fi
+if [ `expr x"$CLVMD" : '.*corosync.*'` != 0 ]; then
+       BUILDCOROSYNC=yes
+       CLVMD_CMANAGERS="$CLVMD_CMANAGERS corosync"
+fi
+if [ `expr x"$CLVMD" : '.*openais.*'` != 0 ]; then
+       BUILDOPENAIS=yes
+       CLVMD_CMANAGERS="$CLVMD_CMANAGERS openais"
+fi
+if test x$CLVMD_NEEDS_QDISKD != xno; then
+       CLVMD_CMANAGERS="$CLVMD_CMANAGERS qdiskd"
 fi
 
-################################################################################
-if [ "x$BUILD_CMIRRORD" = xyes ]; then
-               if  test x$PKGCONFIG_INIT != x1; then
-               pkg_config_init
-       fi
+soft_bailout() {
+       NOTFOUND=1
+}
 
-pkg_failed=no
-{ $as_echo "$as_me:$LINENO: checking for SACKPT" >&5
-$as_echo_n "checking for SACKPT... " >&6; }
+hard_bailout() {
+       as_fn_error $? "bailing out" "$LINENO" 5
+}
 
-if test -n "$SACKPT_CFLAGS"; then
-    pkg_cv_SACKPT_CFLAGS="$SACKPT_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libSaCkpt\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libSaCkpt") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_SACKPT_CFLAGS=`$PKG_CONFIG --cflags "libSaCkpt" 2>/dev/null`
+if test x$CLVMD = xall; then
+       bailout=soft_bailout
+       BUILDCMAN=yes
+       BUILDCOROSYNC=yes
+       BUILDOPENAIS=yes
 else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
+       bailout=hard_bailout
 fi
-if test -n "$SACKPT_LIBS"; then
-    pkg_cv_SACKPT_LIBS="$SACKPT_LIBS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libSaCkpt\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libSaCkpt") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_SACKPT_LIBS=`$PKG_CONFIG --libs "libSaCkpt" 2>/dev/null`
+
+check_lib_no_libs() {
+       lib_no_libs_arg1=$1
+       shift
+       lib_no_libs_arg2=$1
+       shift
+       lib_no_libs_args=$@
+       as_ac_Lib=`$as_echo "ac_cv_lib_$lib_no_libs_arg1''_$lib_no_libs_arg2" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $lib_no_libs_arg2 in -l$lib_no_libs_arg1" >&5
+$as_echo_n "checking for $lib_no_libs_arg2 in -l$lib_no_libs_arg1... " >&6; }
+if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
+  $as_echo_n "(cached) " >&6
 else
-  pkg_failed=yes
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-l$lib_no_libs_arg1 $lib_no_libs_args $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $lib_no_libs_arg2 ();
+int
+main ()
+{
+return $lib_no_libs_arg2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$as_ac_Lib=yes"
+else
+  eval "$as_ac_Lib=no"
 fi
- else
-    pkg_failed=untried
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
 fi
+eval ac_res=\$$as_ac_Lib
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_LIB$lib_no_libs_arg1" | $as_tr_cpp` 1
+_ACEOF
 
+  LIBS="-l$lib_no_libs_arg1 $LIBS"
 
-
-if test $pkg_failed = yes; then
-
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
 else
-        _pkg_short_errors_supported=no
+  $bailout
 fi
-        if test $_pkg_short_errors_supported = yes; then
-               SACKPT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libSaCkpt" 2>&1`
-        else
-               SACKPT_PKG_ERRORS=`$PKG_CONFIG --print-errors "libSaCkpt" 2>&1`
-        fi
-       # Put the nasty error message in config.log where it belongs
-       echo "$SACKPT_PKG_ERRORS" >&5
-
-       { { $as_echo "$as_me:$LINENO: error: Package requirements (libSaCkpt) were not met:
-
-$SACKPT_PKG_ERRORS
-
-Consider adjusting the PKG_CONFIG_PATH environment variable if you
-installed software in a non-standard prefix.
-
-Alternatively, you may set the environment variables SACKPT_CFLAGS
-and SACKPT_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details.
-" >&5
-$as_echo "$as_me: error: Package requirements (libSaCkpt) were not met:
-
-$SACKPT_PKG_ERRORS
-
-Consider adjusting the PKG_CONFIG_PATH environment variable if you
-installed software in a non-standard prefix.
-
-Alternatively, you may set the environment variables SACKPT_CFLAGS
-and SACKPT_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details.
-" >&2;}
-   { (exit 1); exit 1; }; }
-elif test $pkg_failed = untried; then
-       { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-{ { $as_echo "$as_me:$LINENO: error: The pkg-config script could not be found or is too old.  Make sure it
-is in your PATH or set the PKG_CONFIG environment variable to the full
-path to pkg-config.
-
-Alternatively, you may set the environment variables SACKPT_CFLAGS
-and SACKPT_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details.
-
-To get pkg-config, see <http://pkg-config.freedesktop.org/>.
-See \`config.log' for more details." >&5
-$as_echo "$as_me: error: The pkg-config script could not be found or is too old.  Make sure it
-is in your PATH or set the PKG_CONFIG environment variable to the full
-path to pkg-config.
 
-Alternatively, you may set the environment variables SACKPT_CFLAGS
-and SACKPT_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details.
+       LIBS=$ac_check_lib_save_LIBS
+}
 
-To get pkg-config, see <http://pkg-config.freedesktop.org/>.
-See \`config.log' for more details." >&2;}
-   { (exit 1); exit 1; }; }; }
-else
-       SACKPT_CFLAGS=$pkg_cv_SACKPT_CFLAGS
-       SACKPT_LIBS=$pkg_cv_SACKPT_LIBS
-        { $as_echo "$as_me:$LINENO: result: yes" >&5
-$as_echo "yes" >&6; }
-       :
-fi
-       if test x$HAVE_CPG != xyes; then
+if test x$BUILDCMAN = xyes; then
 
 pkg_failed=no
-{ $as_echo "$as_me:$LINENO: checking for CPG" >&5
-$as_echo_n "checking for CPG... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CMAN" >&5
+$as_echo_n "checking for CMAN... " >&6; }
 
-if test -n "$CPG_CFLAGS"; then
-    pkg_cv_CPG_CFLAGS="$CPG_CFLAGS"
+if test -n "$CMAN_CFLAGS"; then
+    pkg_cv_CMAN_CFLAGS="$CMAN_CFLAGS"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libcpg\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libcpg") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcman\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libcman") 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_CPG_CFLAGS=`$PKG_CONFIG --cflags "libcpg" 2>/dev/null`
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_CMAN_CFLAGS=`$PKG_CONFIG --cflags "libcman" 2>/dev/null`
 else
   pkg_failed=yes
 fi
  else
     pkg_failed=untried
 fi
-if test -n "$CPG_LIBS"; then
-    pkg_cv_CPG_LIBS="$CPG_LIBS"
+if test -n "$CMAN_LIBS"; then
+    pkg_cv_CMAN_LIBS="$CMAN_LIBS"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
-    { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libcpg\"") >&5
-  ($PKG_CONFIG --exists --print-errors "libcpg") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcman\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libcman") 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  pkg_cv_CPG_LIBS=`$PKG_CONFIG --libs "libcpg" 2>/dev/null`
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_CMAN_LIBS=`$PKG_CONFIG --libs "libcman" 2>/dev/null`
 else
   pkg_failed=yes
 fi
@@ -14001,6 +7564,8 @@ fi
 
 
 if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
         _pkg_short_errors_supported=yes
         _pkg_short_errors_supported=no
 fi
         if test $_pkg_short_errors_supported = yes; then
-               CPG_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libcpg" 2>&1`
+               CMAN_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libcman" 2>&1`
         else
-               CPG_PKG_ERRORS=`$PKG_CONFIG --print-errors "libcpg" 2>&1`
+               CMAN_PKG_ERRORS=`$PKG_CONFIG --print-errors "libcman" 2>&1`
         fi
        # Put the nasty error message in config.log where it belongs
-       echo "$CPG_PKG_ERRORS" >&5
-
-       { { $as_echo "$as_me:$LINENO: error: Package requirements (libcpg) were not met:
-
-$CPG_PKG_ERRORS
-
-Consider adjusting the PKG_CONFIG_PATH environment variable if you
-installed software in a non-standard prefix.
-
-Alternatively, you may set the environment variables CPG_CFLAGS
-and CPG_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details.
-" >&5
-$as_echo "$as_me: error: Package requirements (libcpg) were not met:
-
-$CPG_PKG_ERRORS
-
-Consider adjusting the PKG_CONFIG_PATH environment variable if you
-installed software in a non-standard prefix.
-
-Alternatively, you may set the environment variables CPG_CFLAGS
-and CPG_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details.
-" >&2;}
-   { (exit 1); exit 1; }; }
-elif test $pkg_failed = untried; then
-       { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-{ { $as_echo "$as_me:$LINENO: error: The pkg-config script could not be found or is too old.  Make sure it
-is in your PATH or set the PKG_CONFIG environment variable to the full
-path to pkg-config.
-
-Alternatively, you may set the environment variables CPG_CFLAGS
-and CPG_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details.
-
-To get pkg-config, see <http://pkg-config.freedesktop.org/>.
-See \`config.log' for more details." >&5
-$as_echo "$as_me: error: The pkg-config script could not be found or is too old.  Make sure it
-is in your PATH or set the PKG_CONFIG environment variable to the full
-path to pkg-config.
-
-Alternatively, you may set the environment variables CPG_CFLAGS
-and CPG_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details.
-
-To get pkg-config, see <http://pkg-config.freedesktop.org/>.
-See \`config.log' for more details." >&2;}
-   { (exit 1); exit 1; }; }; }
-else
-       CPG_CFLAGS=$pkg_cv_CPG_CFLAGS
-       CPG_LIBS=$pkg_cv_CPG_LIBS
-        { $as_echo "$as_me:$LINENO: result: yes" >&5
-$as_echo "yes" >&6; }
-       :
-fi
-       fi
-fi
-
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to enable debugging" >&5
-$as_echo_n "checking whether to enable debugging... " >&6; }
-# Check whether --enable-debug was given.
-if test "${enable_debug+set}" = set; then
-  enableval=$enable_debug; DEBUG=$enableval
-else
-  DEBUG=no
-fi
-
-{ $as_echo "$as_me:$LINENO: result: $DEBUG" >&5
-$as_echo "$DEBUG" >&6; }
-
-if test x$DEBUG = xyes; then
-       COPTIMISE_FLAG=
-else
-       CSCOPE_CMD=
-fi
-
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking for C optimisation flag" >&5
-$as_echo_n "checking for C optimisation flag... " >&6; }
-
-# Check whether --with-optimisation was given.
-if test "${with_optimisation+set}" = set; then
-  withval=$with_optimisation; COPTIMISE_FLAG=$withval
-fi
-
-{ $as_echo "$as_me:$LINENO: result: $COPTIMISE_FLAG" >&5
-$as_echo "$COPTIMISE_FLAG" >&6; }
-
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to gather gcov profiling data" >&5
-$as_echo_n "checking whether to gather gcov profiling data... " >&6; }
-# Check whether --enable-profiling was given.
-if test "${enable_profiling+set}" = set; then
-  enableval=$enable_profiling; PROFILING=$enableval
-else
-  PROFILING=no
-fi
-
-{ $as_echo "$as_me:$LINENO: result: $PROFILING" >&5
-$as_echo "$PROFILING" >&6; }
+       echo "$CMAN_PKG_ERRORS" >&5
 
-if test "x$PROFILING" = xyes; then
-  COPTIMISE_FLAG="$COPTIMISE_FLAG -fprofile-arcs -ftest-coverage"
-  # Extract the first word of "lcov", so it can be a program name with args.
-set dummy lcov; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_path_LCOV+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  case $LCOV in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_LCOV="$LCOV" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_path_LCOV="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
+       NOTFOUND=0
+               for ac_header in libcman.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "libcman.h" "ac_cv_header_libcman_h" "$ac_includes_default"
+if test "x$ac_cv_header_libcman_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBCMAN_H 1
+_ACEOF
 
-  ;;
-esac
-fi
-LCOV=$ac_cv_path_LCOV
-if test -n "$LCOV"; then
-  { $as_echo "$as_me:$LINENO: result: $LCOV" >&5
-$as_echo "$LCOV" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
+  $bailout
 fi
 
-
-  # Extract the first word of "genhtml", so it can be a program name with args.
-set dummy genhtml; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_path_GENHTML+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  case $GENHTML in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_GENHTML="$GENHTML" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_path_GENHTML="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
 done
-done
-IFS=$as_save_IFS
 
-  ;;
-esac
-fi
-GENHTML=$ac_cv_path_GENHTML
-if test -n "$GENHTML"; then
-  { $as_echo "$as_me:$LINENO: result: $GENHTML" >&5
-$as_echo "$GENHTML" >&6; }
-else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+               check_lib_no_libs cman cman_init
+               if test $NOTFOUND = 0; then
+                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no pkg for libcman, using -lcman" >&5
+$as_echo "no pkg for libcman, using -lcman" >&6; }
+                       CMAN_LIBS="-lcman"
+                       HAVE_CMAN=yes
+               fi
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-fi
-
-
-  if test -z "$LCOV" -o -z "$GENHTML"; then
-    { { $as_echo "$as_me:$LINENO: error: lcov and genhtml are required for profiling" >&5
-$as_echo "$as_me: error: lcov and genhtml are required for profiling" >&2;}
-   { (exit 1); exit 1; }; }
-  fi
-  # Extract the first word of "genpng", so it can be a program name with args.
-set dummy genpng; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_path_GENPNG+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  case $GENPNG in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_GENPNG="$GENPNG" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_path_GENPNG="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
+       NOTFOUND=0
+               for ac_header in libcman.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "libcman.h" "ac_cv_header_libcman_h" "$ac_includes_default"
+if test "x$ac_cv_header_libcman_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBCMAN_H 1
+_ACEOF
 
-  ;;
-esac
-fi
-GENPNG=$ac_cv_path_GENPNG
-if test -n "$GENPNG"; then
-  { $as_echo "$as_me:$LINENO: result: $GENPNG" >&5
-$as_echo "$GENPNG" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
+  $bailout
 fi
 
+done
 
-  if test -n "$GENPNG"; then
-    { $as_echo "$as_me:$LINENO: checking whether $GENPNG has all required modules" >&5
-$as_echo_n "checking whether $GENPNG has all required modules... " >&6; }
-    if $GENPNG --help > /dev/null 2>&1 ; then
-      { $as_echo "$as_me:$LINENO: result: ok" >&5
-$as_echo "ok" >&6; }
-      GENHTML="$GENHTML --frames"
-    else
-      { $as_echo "$as_me:$LINENO: result: not supported" >&5
-$as_echo "not supported" >&6; }
-      { $as_echo "$as_me:$LINENO: WARNING: GD.pm perl module is not installed" >&5
-$as_echo "$as_me: WARNING: GD.pm perl module is not installed" >&2;}
-      GENPNG=
-    fi
-  fi
+               check_lib_no_libs cman cman_init
+               if test $NOTFOUND = 0; then
+                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no pkg for libcman, using -lcman" >&5
+$as_echo "no pkg for libcman, using -lcman" >&6; }
+                       CMAN_LIBS="-lcman"
+                       HAVE_CMAN=yes
+               fi
+else
+       CMAN_CFLAGS=$pkg_cv_CMAN_CFLAGS
+       CMAN_LIBS=$pkg_cv_CMAN_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+       HAVE_CMAN=yes
+fi
+       CHECKCONFDB=yes
+       CHECKDLM=yes
 fi
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to enable unit testing" >&5
-$as_echo_n "checking whether to enable unit testing... " >&6; }
-# Check whether --enable-testing was given.
-if test "${enable_testing+set}" = set; then
-  enableval=$enable_testing; TESTING=$enableval
+if test x$BUILDCOROSYNC = xyes || \
+   test x$BUILDOPENAIS = xyes; then
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for COROSYNC" >&5
+$as_echo_n "checking for COROSYNC... " >&6; }
+
+if test -n "$COROSYNC_CFLAGS"; then
+    pkg_cv_COROSYNC_CFLAGS="$COROSYNC_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"corosync\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "corosync") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_COROSYNC_CFLAGS=`$PKG_CONFIG --cflags "corosync" 2>/dev/null`
 else
-  TESTING=no
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$COROSYNC_LIBS"; then
+    pkg_cv_COROSYNC_LIBS="$COROSYNC_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"corosync\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "corosync") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_COROSYNC_LIBS=`$PKG_CONFIG --libs "corosync" 2>/dev/null`
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
 fi
 
-{ $as_echo "$as_me:$LINENO: result: $TESTING" >&5
-$as_echo "$TESTING" >&6; }
 
-if test "$TESTING" = yes; then
-   # Extract the first word of "ruby1.9", so it can be a program name with args.
-set dummy ruby1.9; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_path_RUBY19+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  case $RUBY19 in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_RUBY19="$RUBY19" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_path_RUBY19="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
 
-  ;;
-esac
-fi
-RUBY19=$ac_cv_path_RUBY19
-if test -n "$RUBY19"; then
-  { $as_echo "$as_me:$LINENO: result: $RUBY19" >&5
-$as_echo "$RUBY19" >&6; }
+if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+               COROSYNC_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "corosync" 2>&1`
+        else
+               COROSYNC_PKG_ERRORS=`$PKG_CONFIG --print-errors "corosync" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$COROSYNC_PKG_ERRORS" >&5
+
+       $bailout
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
+       $bailout
+else
+       COROSYNC_CFLAGS=$pkg_cv_COROSYNC_CFLAGS
+       COROSYNC_LIBS=$pkg_cv_COROSYNC_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+       HAVE_COROSYNC=yes
+fi
+       CHECKCONFDB=yes
+       CHECKCMAP=yes
 fi
 
+if test x$BUILDCOROSYNC = xyes; then
 
-   # Extract the first word of "valgrind", so it can be a program name with args.
-set dummy valgrind; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_path_VALGRIND+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  case $VALGRIND in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_VALGRIND="$VALGRIND" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_path_VALGRIND="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for QUORUM" >&5
+$as_echo_n "checking for QUORUM... " >&6; }
 
-  ;;
-esac
+if test -n "$QUORUM_CFLAGS"; then
+    pkg_cv_QUORUM_CFLAGS="$QUORUM_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libquorum\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libquorum") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_QUORUM_CFLAGS=`$PKG_CONFIG --cflags "libquorum" 2>/dev/null`
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
 fi
-VALGRIND=$ac_cv_path_VALGRIND
-if test -n "$VALGRIND"; then
-  { $as_echo "$as_me:$LINENO: result: $VALGRIND" >&5
-$as_echo "$VALGRIND" >&6; }
+if test -n "$QUORUM_LIBS"; then
+    pkg_cv_QUORUM_LIBS="$QUORUM_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libquorum\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libquorum") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_QUORUM_LIBS=`$PKG_CONFIG --libs "libquorum" 2>/dev/null`
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
 fi
 
 
-   if test -z "$RUBY19" -o -z "$VALGRIND"; then
-       { { $as_echo "$as_me:$LINENO: error: ruby1.9 and valgrind are required for testing" >&5
-$as_echo "$as_me: error: ruby1.9 and valgrind are required for testing" >&2;}
-   { (exit 1); exit 1; }; }
-   fi
+
+if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
 fi
+        if test $_pkg_short_errors_supported = yes; then
+               QUORUM_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libquorum" 2>&1`
+        else
+               QUORUM_PKG_ERRORS=`$PKG_CONFIG --print-errors "libquorum" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$QUORUM_PKG_ERRORS" >&5
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to enable valgrind awareness of pools" >&5
-$as_echo_n "checking whether to enable valgrind awareness of pools... " >&6; }
-# Check whether --enable-valgrind_pool was given.
-if test "${enable_valgrind_pool+set}" = set; then
-  enableval=$enable_valgrind_pool; VALGRIND_POOL=$enableval
+       $bailout
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       $bailout
 else
-  VALGRIND_POOL=no
+       QUORUM_CFLAGS=$pkg_cv_QUORUM_CFLAGS
+       QUORUM_LIBS=$pkg_cv_QUORUM_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+       HAVE_QUORUM=yes
+fi
+       CHECKCPG=yes
+       CHECKDLM=yes
 fi
 
-{ $as_echo "$as_me:$LINENO: result: $VALGRIND_POOL" >&5
-$as_echo "$VALGRIND_POOL" >&6; }
+if test x$BUILDOPENAIS = xyes; then
 
-if test "$VALGRIND_POOL" = yes; then
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SALCK" >&5
+$as_echo_n "checking for SALCK... " >&6; }
 
-for ac_header in valgrind/memcheck.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+if test -n "$SALCK_CFLAGS"; then
+    pkg_cv_SALCK_CFLAGS="$SALCK_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libSaLck\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libSaLck") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_SALCK_CFLAGS=`$PKG_CONFIG --cflags "libSaLck" 2>/dev/null`
 else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$SALCK_LIBS"; then
+    pkg_cv_SALCK_LIBS="$SALCK_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libSaLck\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libSaLck") 2>&5
   ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_SALCK_LIBS=`$PKG_CONFIG --libs "libSaLck" 2>/dev/null`
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+               SALCK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libSaLck" 2>&1`
+        else
+               SALCK_PKG_ERRORS=`$PKG_CONFIG --print-errors "libSaLck" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$SALCK_PKG_ERRORS" >&5
 
-       ac_header_compiler=no
+       $bailout
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       $bailout
+else
+       SALCK_CFLAGS=$pkg_cv_SALCK_CFLAGS
+       SALCK_LIBS=$pkg_cv_SALCK_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+       HAVE_SALCK=yes
+fi
+       CHECKCPG=yes
 fi
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
 
-  ac_header_preproc=no
-fi
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
+if test x$CHECKCONFDB = xyes; then
 
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CONFDB" >&5
+$as_echo_n "checking for CONFDB... " >&6; }
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
+if test -n "$CONFDB_CFLAGS"; then
+    pkg_cv_CONFDB_CFLAGS="$CONFDB_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libconfdb\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libconfdb") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_CONFDB_CFLAGS=`$PKG_CONFIG --cflags "libconfdb" 2>/dev/null`
 else
-  eval "$as_ac_Header=\$ac_header_preproc"
+  pkg_failed=yes
 fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-
+ else
+    pkg_failed=untried
 fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
+if test -n "$CONFDB_LIBS"; then
+    pkg_cv_CONFDB_LIBS="$CONFDB_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libconfdb\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libconfdb") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_CONFDB_LIBS=`$PKG_CONFIG --libs "libconfdb" 2>/dev/null`
 else
-  { { $as_echo "$as_me:$LINENO: error: bailing out" >&5
-$as_echo "$as_me: error: bailing out" >&2;}
-   { (exit 1); exit 1; }; }
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
 fi
 
-done
 
 
-cat >>confdefs.h <<\_ACEOF
-#define VALGRIND_POOL 1
-_ACEOF
+if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
 fi
+        if test $_pkg_short_errors_supported = yes; then
+               CONFDB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libconfdb" 2>&1`
+        else
+               CONFDB_PKG_ERRORS=`$PKG_CONFIG --print-errors "libconfdb" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$CONFDB_PKG_ERRORS" >&5
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to use device-mapper" >&5
-$as_echo_n "checking whether to use device-mapper... " >&6; }
-# Check whether --enable-devmapper was given.
-if test "${enable_devmapper+set}" = set; then
-  enableval=$enable_devmapper; DEVMAPPER=$enableval
+       HAVE_CONFDB=no
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       HAVE_CONFDB=no
+else
+       CONFDB_CFLAGS=$pkg_cv_CONFDB_CFLAGS
+       CONFDB_LIBS=$pkg_cv_CONFDB_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+       HAVE_CONFDB=yes
 fi
 
-{ $as_echo "$as_me:$LINENO: result: $DEVMAPPER" >&5
-$as_echo "$DEVMAPPER" >&6; }
+       for ac_header in corosync/confdb.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "corosync/confdb.h" "ac_cv_header_corosync_confdb_h" "$ac_includes_default"
+if test "x$ac_cv_header_corosync_confdb_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_COROSYNC_CONFDB_H 1
+_ACEOF
+ HAVE_CONFDB_H=yes
+else
+  HAVE_CONFDB_H=no
+fi
 
-if test x$DEVMAPPER = xyes; then
+done
 
-cat >>confdefs.h <<\_ACEOF
-#define DEVMAPPER_SUPPORT 1
-_ACEOF
 
+       if test x$HAVE_CONFDB != xyes && \
+          test x$HAVE_CONFDB_H = xyes; then
+               check_lib_no_libs confdb confdb_initialize
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no pkg for confdb, using -lconfdb" >&5
+$as_echo "no pkg for confdb, using -lconfdb" >&6; }
+               CONFDB_LIBS="-lconfdb"
+               HAVE_CONFDB=yes
+       fi
 fi
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to enable synchronisation with udev processing" >&5
-$as_echo_n "checking whether to enable synchronisation with udev processing... " >&6; }
-# Check whether --enable-udev_sync was given.
-if test "${enable_udev_sync+set}" = set; then
-  enableval=$enable_udev_sync; UDEV_SYNC=$enableval
-else
-  UDEV_SYNC=no
-fi
 
-{ $as_echo "$as_me:$LINENO: result: $UDEV_SYNC" >&5
-$as_echo "$UDEV_SYNC" >&6; }
+if test x$CHECKCMAP = xyes; then
 
-if test x$UDEV_SYNC = xyes; then
-       { $as_echo "$as_me:$LINENO: checking for udev_queue_get_udev_is_active in -ludev" >&5
-$as_echo_n "checking for udev_queue_get_udev_is_active in -ludev... " >&6; }
-if test "${ac_cv_lib_udev_udev_queue_get_udev_is_active+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-ludev  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CMAP" >&5
+$as_echo_n "checking for CMAP... " >&6; }
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char udev_queue_get_udev_is_active ();
-int
-main ()
-{
-return udev_queue_get_udev_is_active ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
+if test -n "$CMAP_CFLAGS"; then
+    pkg_cv_CMAP_CFLAGS="$CMAP_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcmap\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libcmap") 2>&5
   ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_lib_udev_udev_queue_get_udev_is_active=yes
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_CMAP_CFLAGS=`$PKG_CONFIG --cflags "libcmap" 2>/dev/null`
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_lib_udev_udev_queue_get_udev_is_active=no
+  pkg_failed=yes
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+ else
+    pkg_failed=untried
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_udev_udev_queue_get_udev_is_active" >&5
-$as_echo "$ac_cv_lib_udev_udev_queue_get_udev_is_active" >&6; }
-if test "x$ac_cv_lib_udev_udev_queue_get_udev_is_active" = x""yes; then
-  UDEV_PC="libudev"; UDEV_LIBS="-ludev"
+if test -n "$CMAP_LIBS"; then
+    pkg_cv_CMAP_LIBS="$CMAP_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcmap\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libcmap") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_CMAP_LIBS=`$PKG_CONFIG --libs "libcmap" 2>/dev/null`
 else
-  { { $as_echo "$as_me:$LINENO: error: bailing out... libudev library is required" >&5
-$as_echo "$as_me: error: bailing out... libudev library is required" >&2;}
-   { (exit 1); exit 1; }; }
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
 fi
 
 
-cat >>confdefs.h <<\_ACEOF
-#define UDEV_SYNC_SUPPORT 1
-_ACEOF
 
-fi
+if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 
-{ $as_echo "$as_me:$LINENO: checking whether to enable installation of udev rules required for synchronisation" >&5
-$as_echo_n "checking whether to enable installation of udev rules required for synchronisation... " >&6; }
-# Check whether --enable-udev_rules was given.
-if test "${enable_udev_rules+set}" = set; then
-  enableval=$enable_udev_rules; UDEV_RULES=$enableval
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
 else
-  UDEV_RULES=$UDEV_SYNC
+        _pkg_short_errors_supported=no
 fi
+        if test $_pkg_short_errors_supported = yes; then
+               CMAP_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libcmap" 2>&1`
+        else
+               CMAP_PKG_ERRORS=`$PKG_CONFIG --print-errors "libcmap" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$CMAP_PKG_ERRORS" >&5
 
-{ $as_echo "$as_me:$LINENO: result: $UDEV_RULES" >&5
-$as_echo "$UDEV_RULES" >&6; }
-
-################################################################################
-# Check whether --enable-compat was given.
-if test "${enable_compat+set}" = set; then
-  enableval=$enable_compat; DM_COMPAT=$enableval
+       HAVE_CMAP=no
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       HAVE_CMAP=no
 else
-  DM_COMPAT=no
+       CMAP_CFLAGS=$pkg_cv_CMAP_CFLAGS
+       CMAP_LIBS=$pkg_cv_CMAP_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+       HAVE_CMAP=yes
 fi
 
-
-################################################################################
-# Check whether --enable-units-compat was given.
-if test "${enable_units_compat+set}" = set; then
-  enableval=$enable_units_compat; UNITS_COMPAT=$enableval
+       for ac_header in corosync/cmap.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "corosync/cmap.h" "ac_cv_header_corosync_cmap_h" "$ac_includes_default"
+if test "x$ac_cv_header_corosync_cmap_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_COROSYNC_CMAP_H 1
+_ACEOF
+ HAVE_CMAP_H=yes
 else
-  UNITS_COMPAT=no
+  HAVE_CMAP_H=no
 fi
 
+done
 
-if test x$UNITS_COMPAT = xyes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define DEFAULT_SI_UNIT_CONSISTENCY 0
-_ACEOF
-
-fi
 
-################################################################################
-# Check whether --enable-ioctl was given.
-if test "${enable_ioctl+set}" = set; then
-  enableval=$enable_ioctl; DM_IOCTLS=$enableval
+       if test x$HAVE_CMAP != xyes && \
+          test x$HAVE_CMAP_H = xyes; then
+               check_lib_no_libs cmap cmap_initialize
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no pkg for cmap, using -lcmap" >&5
+$as_echo "no pkg for cmap, using -lcmap" >&6; }
+               CMAP_LIBS="-lcmap"
+               HAVE_CMAP=yes
+       fi
 fi
 
-
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to enable O_DIRECT" >&5
-$as_echo_n "checking whether to enable O_DIRECT... " >&6; }
-# Check whether --enable-o_direct was given.
-if test "${enable_o_direct+set}" = set; then
-  enableval=$enable_o_direct; ODIRECT=$enableval
+if test x$BUILDCOROSYNC = xyes; then
+       if test x$HAVE_CMAP != xyes && \
+          test x$HAVE_CONFDB != xyes && \
+          test x$CLVMD != xall; then
+               as_fn_error $? "bailing out... cmap (corosync >= 2.0) or confdb (corosync < 2.0) library is required" "$LINENO" 5
+       fi
 fi
 
-{ $as_echo "$as_me:$LINENO: result: $ODIRECT" >&5
-$as_echo "$ODIRECT" >&6; }
-
-if test x$ODIRECT = xyes; then
+if test x$CHECKCPG = xyes; then
 
-cat >>confdefs.h <<\_ACEOF
-#define O_DIRECT_SUPPORT 1
-_ACEOF
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CPG" >&5
+$as_echo_n "checking for CPG... " >&6; }
 
+if test -n "$CPG_CFLAGS"; then
+    pkg_cv_CPG_CFLAGS="$CPG_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcpg\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libcpg") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_CPG_CFLAGS=`$PKG_CONFIG --cflags "libcpg" 2>/dev/null`
+else
+  pkg_failed=yes
 fi
-
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to build liblvm2app.so application library" >&5
-$as_echo_n "checking whether to build liblvm2app.so application library... " >&6; }
-# Check whether --enable-applib was given.
-if test "${enable_applib+set}" = set; then
-  enableval=$enable_applib; APPLIB=$enableval
+ else
+    pkg_failed=untried
+fi
+if test -n "$CPG_LIBS"; then
+    pkg_cv_CPG_LIBS="$CPG_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcpg\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libcpg") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_CPG_LIBS=`$PKG_CONFIG --libs "libcpg" 2>/dev/null`
 else
-  APPLIB=no
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
 fi
 
-{ $as_echo "$as_me:$LINENO: result: $APPLIB" >&5
-$as_echo "$APPLIB" >&6; }
 
-test x$APPLIB = xyes \
-  && LVM2APP_LIB=-llvm2app \
-  || LVM2APP_LIB=
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to compile liblvm2cmd.so" >&5
-$as_echo_n "checking whether to compile liblvm2cmd.so... " >&6; }
-# Check whether --enable-cmdlib was given.
-if test "${enable_cmdlib+set}" = set; then
-  enableval=$enable_cmdlib; CMDLIB=$enableval
+if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
 else
-  CMDLIB=no
+        _pkg_short_errors_supported=no
 fi
+        if test $_pkg_short_errors_supported = yes; then
+               CPG_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libcpg" 2>&1`
+        else
+               CPG_PKG_ERRORS=`$PKG_CONFIG --print-errors "libcpg" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$CPG_PKG_ERRORS" >&5
 
-{ $as_echo "$as_me:$LINENO: result: $CMDLIB" >&5
-$as_echo "$CMDLIB" >&6; }
-
-test x$CMDLIB = xyes \
-  && LVM2CMD_LIB=-llvm2cmd \
-  || LVM2CMD_LIB=
-
-################################################################################
-# Check whether --enable-pkgconfig was given.
-if test "${enable_pkgconfig+set}" = set; then
-  enableval=$enable_pkgconfig; PKGCONFIG=$enableval
+       $bailout
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       $bailout
 else
-  PKGCONFIG=no
+       CPG_CFLAGS=$pkg_cv_CPG_CFLAGS
+       CPG_LIBS=$pkg_cv_CPG_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+       HAVE_CPG=yes
+fi
 fi
 
+if test x$CHECKDLM = xyes; then
 
-################################################################################
-# Check whether --enable-write_install was given.
-if test "${enable_write_install+set}" = set; then
-  enableval=$enable_write_install; WRITE_INSTALL=$enableval
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for DLM" >&5
+$as_echo_n "checking for DLM... " >&6; }
+
+if test -n "$DLM_CFLAGS"; then
+    pkg_cv_DLM_CFLAGS="$DLM_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdlm\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libdlm") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_DLM_CFLAGS=`$PKG_CONFIG --cflags "libdlm" 2>/dev/null`
 else
-  WRITE_INSTALL=no
+  pkg_failed=yes
 fi
-
-
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to install fsadm" >&5
-$as_echo_n "checking whether to install fsadm... " >&6; }
-# Check whether --enable-fsadm was given.
-if test "${enable_fsadm+set}" = set; then
-  enableval=$enable_fsadm; FSADM=$enableval
+ else
+    pkg_failed=untried
 fi
-
-{ $as_echo "$as_me:$LINENO: result: $FSADM" >&5
-$as_echo "$FSADM" >&6; }
-
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to use dmeventd" >&5
-$as_echo_n "checking whether to use dmeventd... " >&6; }
-# Check whether --enable-dmeventd was given.
-if test "${enable_dmeventd+set}" = set; then
-  enableval=$enable_dmeventd; DMEVENTD=$enableval
+if test -n "$DLM_LIBS"; then
+    pkg_cv_DLM_LIBS="$DLM_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdlm\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libdlm") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_DLM_LIBS=`$PKG_CONFIG --libs "libdlm" 2>/dev/null`
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
 fi
 
-{ $as_echo "$as_me:$LINENO: result: $DMEVENTD" >&5
-$as_echo "$DMEVENTD" >&6; }
 
-BUILD_DMEVENTD=$DMEVENTD
 
-if test x$DMEVENTD = xyes; then
-   if test x$MIRRORS != xinternal; then
-      { { $as_echo "$as_me:$LINENO: error: --enable-dmeventd currently requires --with-mirrors=internal
-      " >&5
-$as_echo "$as_me: error: --enable-dmeventd currently requires --with-mirrors=internal
-      " >&2;}
-   { (exit 1); exit 1; }; }
-   fi
-   if test x$CMDLIB = xno; then
-      { { $as_echo "$as_me:$LINENO: error: --enable-dmeventd requires --enable-cmdlib to be used as well
-      " >&5
-$as_echo "$as_me: error: --enable-dmeventd requires --enable-cmdlib to be used as well
-      " >&2;}
-   { (exit 1); exit 1; }; }
-   fi
-fi
+if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 
-if test x$DMEVENTD = xyes; then
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+               DLM_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libdlm" 2>&1`
+        else
+               DLM_PKG_ERRORS=`$PKG_CONFIG --print-errors "libdlm" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$DLM_PKG_ERRORS" >&5
 
-cat >>confdefs.h <<\_ACEOF
-#define DMEVENTD 1
+       NOTFOUND=0
+               for ac_header in libdlm.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "libdlm.h" "ac_cv_header_libdlm_h" "$ac_includes_default"
+if test "x$ac_cv_header_libdlm_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBDLM_H 1
 _ACEOF
 
+else
+  $bailout
 fi
 
-################################################################################
+done
 
-{ $as_echo "$as_me:$LINENO: checking for getline in -lc" >&5
-$as_echo_n "checking for getline in -lc... " >&6; }
-if test "${ac_cv_lib_c_getline+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lc  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
+               check_lib_no_libs dlm dlm_lock -lpthread
+               if test $NOTFOUND = 0; then
+                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no pkg for libdlm, using -ldlm" >&5
+$as_echo "no pkg for libdlm, using -ldlm" >&6; }
+                       DLM_LIBS="-ldlm -lpthread"
+                       HAVE_DLM=yes
+               fi
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       NOTFOUND=0
+               for ac_header in libdlm.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "libdlm.h" "ac_cv_header_libdlm_h" "$ac_includes_default"
+if test "x$ac_cv_header_libdlm_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBDLM_H 1
 _ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char getline ();
-int
-main ()
-{
-return getline ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_lib_c_getline=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_lib_c_getline=no
+  $bailout
 fi
 
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_c_getline" >&5
-$as_echo "$ac_cv_lib_c_getline" >&6; }
-if test "x$ac_cv_lib_c_getline" = x""yes; then
+done
 
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_GETLINE 1
-_ACEOF
+               check_lib_no_libs dlm dlm_lock -lpthread
+               if test $NOTFOUND = 0; then
+                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no pkg for libdlm, using -ldlm" >&5
+$as_echo "no pkg for libdlm, using -ldlm" >&6; }
+                       DLM_LIBS="-ldlm -lpthread"
+                       HAVE_DLM=yes
+               fi
+else
+       DLM_CFLAGS=$pkg_cv_DLM_CFLAGS
+       DLM_LIBS=$pkg_cv_DLM_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+       HAVE_DLM=yes
+fi
+fi
 
+if test x$CLVMD = xall; then
+       CLVMD=none
+       CLVMD_CMANAGERS=""
+       CLVMD_NEEDS_QDISKD=no
+       if test x$HAVE_CMAN = xyes && \
+          test x$HAVE_DLM = xyes; then
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling clvmd cman cluster manager" >&5
+$as_echo "Enabling clvmd cman cluster manager" >&6; }
+               CLVMD="$CLVMD,cman"
+               CLVMD_CMANAGERS="$CLVMD_CMANAGERS cman"
+               CLVMD_NEEDS_QDISKD=yes
+       fi
+       if test x$HAVE_COROSYNC = xyes && \
+          test x$HAVE_QUORUM = xyes && \
+          test x$HAVE_CPG = xyes && \
+          test x$HAVE_DLM = xyes; then
+          if test x$HAVE_CONFDB = xyes || test x$HAVE_CMAP = xyes; then
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling clvmd corosync cluster manager" >&5
+$as_echo "Enabling clvmd corosync cluster manager" >&6; }
+               CLVMD="$CLVMD,corosync"
+               CLVMD_CMANAGERS="$CLVMD_CMANAGERS corosync"
+          fi
+       fi
+       if test x$HAVE_COROSYNC = xyes && \
+          test x$HAVE_CPG = xyes && \
+          test x$HAVE_SALCK = xyes; then
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling clvmd openais cluster manager" >&5
+$as_echo "Enabling clvmd openais cluster manager" >&6; }
+               CLVMD="$CLVMD,openais"
+               CLVMD_CMANAGERS="$CLVMD_CMANAGERS openais"
+       fi
+       if test x$CLVMD_NEEDS_QDISKD != xno; then
+               CLVMD_CMANAGERS="$CLVMD_CMANAGERS qdiskd"
+       fi
+       if test x$CLVMD = xnone; then
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling clvmd build. No cluster manager detected." >&5
+$as_echo "Disabling clvmd build. No cluster manager detected." >&6; }
+       fi
 fi
 
+if [ `expr x"$CLVMD" : '.*corosync.*'` != 0 ]; then
+   if test x$HAVE_CMAP = xyes; then
+       CLVMD_CMANAGERS="$CLVMD_CMANAGERS dlm"
+   fi
+fi
 
 ################################################################################
+if test "x$CLVMD" != xnone; then
 
-{ $as_echo "$as_me:$LINENO: checking for canonicalize_file_name in -lc" >&5
-$as_echo_n "checking for canonicalize_file_name in -lc... " >&6; }
-if test "${ac_cv_lib_c_canonicalize_file_name+set}" = set; then
-  $as_echo_n "(cached) " >&6
+# Check whether --with-clvmd-pidfile was given.
+if test "${with_clvmd_pidfile+set}" = set; then :
+  withval=$with_clvmd_pidfile; CLVMD_PIDFILE=$withval
 else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lc  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
+  CLVMD_PIDFILE="$DEFAULT_PID_DIR/clvmd.pid"
+fi
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char canonicalize_file_name ();
-int
-main ()
-{
-return canonicalize_file_name ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_lib_c_canonicalize_file_name=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
 
-       ac_cv_lib_c_canonicalize_file_name=no
+cat >>confdefs.h <<_ACEOF
+#define CLVMD_PIDFILE "$CLVMD_PIDFILE"
+_ACEOF
+
 fi
 
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build cluster mirror log daemon" >&5
+$as_echo_n "checking whether to build cluster mirror log daemon... " >&6; }
+# Check whether --enable-cmirrord was given.
+if test "${enable_cmirrord+set}" = set; then :
+  enableval=$enable_cmirrord; CMIRRORD=$enableval
+else
+  CMIRRORD=no
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_c_canonicalize_file_name" >&5
-$as_echo "$ac_cv_lib_c_canonicalize_file_name" >&6; }
-if test "x$ac_cv_lib_c_canonicalize_file_name" = x""yes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_CANONICALIZE_FILE_NAME 1
-_ACEOF
 
-fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CMIRRORD" >&5
+$as_echo "$CMIRRORD" >&6; }
 
+BUILD_CMIRRORD=$CMIRRORD
 
 ################################################################################
-if [ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ];
- then  exec_prefix="";
-fi;
+if test "x$BUILD_CMIRRORD" = xyes; then
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
-$as_echo_n "checking for dlopen in -ldl... " >&6; }
-if test "${ac_cv_lib_dl_dlopen+set}" = set; then
-  $as_echo_n "(cached) " >&6
+# Check whether --with-cmirrord-pidfile was given.
+if test "${with_cmirrord_pidfile+set}" = set; then :
+  withval=$with_cmirrord_pidfile; CMIRRORD_PIDFILE=$withval
 else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldl  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
+  CMIRRORD_PIDFILE="$DEFAULT_PID_DIR/cmirrord.pid"
+fi
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char dlopen ();
-int
-main ()
-{
-return dlopen ();
-  ;
-  return 0;
-}
+
+cat >>confdefs.h <<_ACEOF
+#define CMIRRORD_PIDFILE "$CMIRRORD_PIDFILE"
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_lib_dl_dlopen=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
 
-       ac_cv_lib_dl_dlopen=no
 fi
 
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
-$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
-if test "x$ac_cv_lib_dl_dlopen" = x""yes; then
+################################################################################
+if [ "x$BUILD_CMIRRORD" = xyes ]; then
+               if  test x$PKGCONFIG_INIT != x1; then
+               pkg_config_init
+       fi
 
 
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_LIBDL 1
-_ACEOF
+$as_echo "#define CMIRROR_HAS_CHECKPOINT 1" >>confdefs.h
 
-       DL_LIBS="-ldl"
-       HAVE_LIBDL=yes
-else
 
-       DL_LIBS=
-       HAVE_LIBDL=no
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SACKPT" >&5
+$as_echo_n "checking for SACKPT... " >&6; }
+
+if test -n "$SACKPT_CFLAGS"; then
+    pkg_cv_SACKPT_CFLAGS="$SACKPT_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libSaCkpt\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libSaCkpt") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_SACKPT_CFLAGS=`$PKG_CONFIG --cflags "libSaCkpt" 2>/dev/null`
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$SACKPT_LIBS"; then
+    pkg_cv_SACKPT_LIBS="$SACKPT_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libSaCkpt\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libSaCkpt") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_SACKPT_LIBS=`$PKG_CONFIG --libs "libSaCkpt" 2>/dev/null`
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
 fi
 
 
-################################################################################
-if [ \( "x$LVM1" = xshared -o "x$POOL" = xshared -o "x$CLUSTER" = xshared \
-      -o "x$SNAPSHOTS" = xshared -o "x$MIRRORS" = xshared \
-      \) -a "x$STATIC_LINK" = xyes ];
- then  { { $as_echo "$as_me:$LINENO: error: Features cannot be 'shared' when building statically
-" >&5
-$as_echo "$as_me: error: Features cannot be 'shared' when building statically
-" >&2;}
-   { (exit 1); exit 1; }; }
+
+if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
 fi
+        if test $_pkg_short_errors_supported = yes; then
+               SACKPT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libSaCkpt" 2>&1`
+        else
+               SACKPT_PKG_ERRORS=`$PKG_CONFIG --print-errors "libSaCkpt" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$SACKPT_PKG_ERRORS" >&5
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no libSaCkpt, compiling without it" >&5
+$as_echo "no libSaCkpt, compiling without it" >&6; }
+
+$as_echo "#define CMIRROR_HAS_CHECKPOINT 0" >>confdefs.h
+
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no libSaCkpt, compiling without it" >&5
+$as_echo "no libSaCkpt, compiling without it" >&6; }
+
+$as_echo "#define CMIRROR_HAS_CHECKPOINT 0" >>confdefs.h
 
-################################################################################
-if [ "$DMEVENTD" = yes -o "$CLVMD" != none ] ; then
-       { $as_echo "$as_me:$LINENO: checking for pthread_mutex_lock in -lpthread" >&5
-$as_echo_n "checking for pthread_mutex_lock in -lpthread... " >&6; }
-if test "${ac_cv_lib_pthread_pthread_mutex_lock+set}" = set; then
-  $as_echo_n "(cached) " >&6
 else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lpthread  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
+       SACKPT_CFLAGS=$pkg_cv_SACKPT_CFLAGS
+       SACKPT_LIBS=$pkg_cv_SACKPT_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+       HAVE_SACKPT=yes
+fi
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char pthread_mutex_lock ();
-int
-main ()
-{
-return pthread_mutex_lock ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
+       if test x$HAVE_CPG != xyes; then
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CPG" >&5
+$as_echo_n "checking for CPG... " >&6; }
+
+if test -n "$CPG_CFLAGS"; then
+    pkg_cv_CPG_CFLAGS="$CPG_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcpg\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libcpg") 2>&5
   ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_lib_pthread_pthread_mutex_lock=yes
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_CPG_CFLAGS=`$PKG_CONFIG --cflags "libcpg" 2>/dev/null`
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_lib_pthread_pthread_mutex_lock=no
+  pkg_failed=yes
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+ else
+    pkg_failed=untried
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_pthread_pthread_mutex_lock" >&5
-$as_echo "$ac_cv_lib_pthread_pthread_mutex_lock" >&6; }
-if test "x$ac_cv_lib_pthread_pthread_mutex_lock" = x""yes; then
-  PTHREAD_LIBS="-lpthread"
+if test -n "$CPG_LIBS"; then
+    pkg_cv_CPG_LIBS="$CPG_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcpg\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libcpg") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_CPG_LIBS=`$PKG_CONFIG --libs "libcpg" 2>/dev/null`
 else
-  hard_bailout
+  pkg_failed=yes
 fi
-
+ else
+    pkg_failed=untried
 fi
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to enable selinux support" >&5
-$as_echo_n "checking whether to enable selinux support... " >&6; }
-# Check whether --enable-selinux was given.
-if test "${enable_selinux+set}" = set; then
-  enableval=$enable_selinux; SELINUX=$enableval
-fi
 
-{ $as_echo "$as_me:$LINENO: result: $SELINUX" >&5
-$as_echo "$SELINUX" >&6; }
 
-################################################################################
-if test x$SELINUX = xyes; then
-       { $as_echo "$as_me:$LINENO: checking for sepol_check_context in -lsepol" >&5
-$as_echo_n "checking for sepol_check_context in -lsepol... " >&6; }
-if test "${ac_cv_lib_sepol_sepol_check_context+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lsepol  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
+if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char sepol_check_context ();
-int
-main ()
-{
-return sepol_check_context ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_lib_sepol_sepol_check_context=yes
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_lib_sepol_sepol_check_context=no
+        _pkg_short_errors_supported=no
 fi
+        if test $_pkg_short_errors_supported = yes; then
+               CPG_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libcpg" 2>&1`
+        else
+               CPG_PKG_ERRORS=`$PKG_CONFIG --print-errors "libcpg" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$CPG_PKG_ERRORS" >&5
 
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_sepol_sepol_check_context" >&5
-$as_echo "$ac_cv_lib_sepol_sepol_check_context" >&6; }
-if test "x$ac_cv_lib_sepol_sepol_check_context" = x""yes; then
+       as_fn_error $? "Package requirements (libcpg) were not met:
+
+$CPG_PKG_ERRORS
 
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
 
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_SEPOL 1
-_ACEOF
+Alternatively, you may set the environment variables CPG_CFLAGS
+and CPG_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details." "$LINENO" 5
 
-               SELINUX_LIBS="-lsepol"
-fi
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "The pkg-config script could not be found or is too old.  Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
 
+Alternatively, you may set the environment variables CPG_CFLAGS
+and CPG_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
 
-       { $as_echo "$as_me:$LINENO: checking for is_selinux_enabled in -lselinux" >&5
-$as_echo_n "checking for is_selinux_enabled in -lselinux... " >&6; }
-if test "${ac_cv_lib_selinux_is_selinux_enabled+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lselinux  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.
+See \`config.log' for more details" "$LINENO" 5; }
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char is_selinux_enabled ();
-int
-main ()
-{
-return is_selinux_enabled ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_lib_selinux_is_selinux_enabled=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+       CPG_CFLAGS=$pkg_cv_CPG_CFLAGS
+       CPG_LIBS=$pkg_cv_CPG_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
 
-       ac_cv_lib_selinux_is_selinux_enabled=no
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+       fi
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_selinux_is_selinux_enabled" >&5
-$as_echo "$ac_cv_lib_selinux_is_selinux_enabled" >&6; }
-if test "x$ac_cv_lib_selinux_is_selinux_enabled" = x""yes; then
-
 
-for ac_header in selinux/selinux.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable debugging" >&5
+$as_echo_n "checking whether to enable debugging... " >&6; }
+# Check whether --enable-debug was given.
+if test "${enable_debug+set}" = set; then :
+  enableval=$enable_debug; DEBUG=$enableval
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_header_compiler=no
+  DEBUG=no
 fi
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEBUG" >&5
+$as_echo "$DEBUG" >&6; }
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
+if test x$DEBUG = xyes; then
+       COPTIMISE_FLAG=
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  ac_header_preproc=no
+       CSCOPE_CMD=
 fi
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C optimisation flag" >&5
+$as_echo_n "checking for C optimisation flag... " >&6; }
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  eval "$as_ac_Header=\$ac_header_preproc"
+# Check whether --with-optimisation was given.
+if test "${with_optimisation+set}" = set; then :
+  withval=$with_optimisation; COPTIMISE_FLAG=$withval
 fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 
-fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $COPTIMISE_FLAG" >&5
+$as_echo "$COPTIMISE_FLAG" >&6; }
 
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to gather gcov profiling data" >&5
+$as_echo_n "checking whether to gather gcov profiling data... " >&6; }
+# Check whether --enable-profiling was given.
+if test "${enable_profiling+set}" = set; then :
+  enableval=$enable_profiling; PROFILING=$enableval
 else
-  hard_bailout
+  PROFILING=no
 fi
 
-done
-
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PROFILING" >&5
+$as_echo "$PROFILING" >&6; }
 
-for ac_header in selinux/label.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+if test "x$PROFILING" = xyes; then
+  COPTIMISE_FLAG="$COPTIMISE_FLAG -fprofile-arcs -ftest-coverage"
+  # Extract the first word of "lcov", so it can be a program name with args.
+set dummy lcov; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_path_LCOV+set}" = set; then :
   $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
+  case $LCOV in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_LCOV="$LCOV" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_LCOV="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
+fi
+LCOV=$ac_cv_path_LCOV
+if test -n "$LCOV"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LCOV" >&5
+$as_echo "$LCOV" >&6; }
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_header_compiler=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
+  # Extract the first word of "genhtml", so it can be a program name with args.
+set dummy genhtml; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_path_GENHTML+set}" = set; then :
+  $as_echo_n "(cached) " >&6
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  case $GENHTML in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_GENHTML="$GENHTML" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_GENHTML="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
-  ac_header_preproc=no
+  ;;
+esac
+fi
+GENHTML=$ac_cv_path_GENHTML
+if test -n "$GENHTML"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GENHTML" >&5
+$as_echo "$GENHTML" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
 
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+  if test -z "$LCOV" -o -z "$GENHTML"; then
+    as_fn_error $? "lcov and genhtml are required for profiling" "$LINENO" 5
+  fi
+  # Extract the first word of "genpng", so it can be a program name with args.
+set dummy genpng; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_path_GENPNG+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $GENPNG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_GENPNG="$GENPNG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_GENPNG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
-    ;;
+  ;;
 esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
+fi
+GENPNG=$ac_cv_path_GENPNG
+if test -n "$GENPNG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GENPNG" >&5
+$as_echo "$GENPNG" >&6; }
 else
-  eval "$as_ac_Header=\$ac_header_preproc"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 
-fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
 
+  if test -n "$GENPNG"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $GENPNG has all required modules" >&5
+$as_echo_n "checking whether $GENPNG has all required modules... " >&6; }
+    if $GENPNG --help > /dev/null 2>&1 ; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+      GENHTML="$GENHTML --frames"
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: not supported" >&5
+$as_echo "not supported" >&6; }
+      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: GD.pm perl module is not installed" >&5
+$as_echo "$as_me: WARNING: GD.pm perl module is not installed" >&2;}
+      GENPNG=
+    fi
+  fi
 fi
 
-done
-
-
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_SELINUX 1
-_ACEOF
-
-               SELINUX_LIBS="-lselinux $SELINUX_LIBS"
-               SELINUX_PC="libselinux"
-               HAVE_SELINUX=yes
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable unit testing" >&5
+$as_echo_n "checking whether to enable unit testing... " >&6; }
+# Check whether --enable-testing was given.
+if test "${enable_testing+set}" = set; then :
+  enableval=$enable_testing; TESTING=$enableval
 else
-
-               { $as_echo "$as_me:$LINENO: WARNING: Disabling selinux" >&5
-$as_echo "$as_me: WARNING: Disabling selinux" >&2;}
-               SELINUX_LIBS=
-               SELINUX_PC=
-               HAVE_SELINUX=no
+  TESTING=no
 fi
 
-fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $TESTING" >&5
+$as_echo "$TESTING" >&6; }
 
-################################################################################
-if test x$REALTIME = xyes; then
-       { $as_echo "$as_me:$LINENO: checking for clock_gettime in -lrt" >&5
-$as_echo_n "checking for clock_gettime in -lrt... " >&6; }
-if test "${ac_cv_lib_rt_clock_gettime+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lrt  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
+if test "$TESTING" = yes; then
+       if  test x$PKGCONFIG_INIT != x1; then
+               pkg_config_init
+       fi
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char clock_gettime ();
-int
-main ()
-{
-return clock_gettime ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CUNIT" >&5
+$as_echo_n "checking for CUNIT... " >&6; }
+
+if test -n "$CUNIT_CFLAGS"; then
+    pkg_cv_CUNIT_CFLAGS="$CUNIT_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"cunit >= 2.0\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "cunit >= 2.0") 2>&5
   ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_lib_rt_clock_gettime=yes
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_CUNIT_CFLAGS=`$PKG_CONFIG --cflags "cunit >= 2.0" 2>/dev/null`
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_lib_rt_clock_gettime=no
+  pkg_failed=yes
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+ else
+    pkg_failed=untried
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_rt_clock_gettime" >&5
-$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; }
-if test "x$ac_cv_lib_rt_clock_gettime" = x""yes; then
-  HAVE_REALTIME=yes
+if test -n "$CUNIT_LIBS"; then
+    pkg_cv_CUNIT_LIBS="$CUNIT_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"cunit >= 2.0\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "cunit >= 2.0") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_CUNIT_LIBS=`$PKG_CONFIG --libs "cunit >= 2.0" 2>/dev/null`
 else
-  HAVE_REALTIME=no
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
 fi
 
 
-       if test x$HAVE_REALTIME = xyes; then
 
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_REALTIME 1
-_ACEOF
+if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 
-               LIBS="-lrt $LIBS"
-       else
-               { $as_echo "$as_me:$LINENO: WARNING: Disabling realtime clock" >&5
-$as_echo "$as_me: WARNING: Disabling realtime clock" >&2;}
-       fi
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
 fi
+        if test $_pkg_short_errors_supported = yes; then
+               CUNIT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "cunit >= 2.0" 2>&1`
+        else
+               CUNIT_PKG_ERRORS=`$PKG_CONFIG --print-errors "cunit >= 2.0" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$CUNIT_PKG_ERRORS" >&5
 
-################################################################################
-
-for ac_header in getopt.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+       as_fn_error $? "Package requirements (cunit >= 2.0) were not met:
 
-       ac_header_compiler=no
-fi
+$CUNIT_PKG_ERRORS
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+Alternatively, you may set the environment variables CUNIT_CFLAGS
+and CUNIT_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details." "$LINENO" 5
 
-  ac_header_preproc=no
-fi
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "The pkg-config script could not be found or is too old.  Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
+Alternatively, you may set the environment variables CUNIT_CFLAGS
+and CUNIT_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
 
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.
+See \`config.log' for more details" "$LINENO" 5; }
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
 else
-  eval "$as_ac_Header=\$ac_header_preproc"
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+       CUNIT_CFLAGS=$pkg_cv_CUNIT_CFLAGS
+       CUNIT_LIBS=$pkg_cv_CUNIT_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
 
 fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_GETOPTLONG 1
-_ACEOF
+fi
 
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable valgrind awareness of pools" >&5
+$as_echo_n "checking whether to enable valgrind awareness of pools... " >&6; }
+# Check whether --enable-valgrind_pool was given.
+if test "${enable_valgrind_pool+set}" = set; then :
+  enableval=$enable_valgrind_pool; VALGRIND_POOL=$enableval
+else
+  VALGRIND_POOL=no
 fi
 
-done
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $VALGRIND_POOL" >&5
+$as_echo "$VALGRIND_POOL" >&6; }
 
+if test "$VALGRIND_POOL" = yes; then
 
-################################################################################
-if test x$READLINE != xno; then
-       lvm_saved_libs=$LIBS
-       { $as_echo "$as_me:$LINENO: checking for library containing tgetent" >&5
-$as_echo_n "checking for library containing tgetent... " >&6; }
-if test "${ac_cv_search_tgetent+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_func_search_save_LIBS=$LIBS
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for VALGRIND" >&5
+$as_echo_n "checking for VALGRIND... " >&6; }
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char tgetent ();
-int
-main ()
-{
-return tgetent ();
-  ;
-  return 0;
-}
-_ACEOF
-for ac_lib in '' tinfo ncurses curses termcap termlib; do
-  if test -z "$ac_lib"; then
-    ac_res="none required"
-  else
-    ac_res=-l$ac_lib
-    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
-  fi
-  rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
+if test -n "$VALGRIND_CFLAGS"; then
+    pkg_cv_VALGRIND_CFLAGS="$VALGRIND_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"valgrind\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "valgrind") 2>&5
   ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_search_tgetent=$ac_res
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_VALGRIND_CFLAGS=`$PKG_CONFIG --cflags "valgrind" 2>/dev/null`
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$VALGRIND_LIBS"; then
+    pkg_cv_VALGRIND_LIBS="$VALGRIND_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"valgrind\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "valgrind") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_VALGRIND_LIBS=`$PKG_CONFIG --libs "valgrind" 2>/dev/null`
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
 
 
-fi
 
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext
-  if test "${ac_cv_search_tgetent+set}" = set; then
-  break
+if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
 fi
-done
-if test "${ac_cv_search_tgetent+set}" = set; then
-  :
+        if test $_pkg_short_errors_supported = yes; then
+               VALGRIND_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "valgrind" 2>&1`
+        else
+               VALGRIND_PKG_ERRORS=`$PKG_CONFIG --print-errors "valgrind" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$VALGRIND_PKG_ERRORS" >&5
+
+       as_fn_error $? "bailing out" "$LINENO" 5
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       as_fn_error $? "bailing out" "$LINENO" 5
 else
-  ac_cv_search_tgetent=no
+       VALGRIND_CFLAGS=$pkg_cv_VALGRIND_CFLAGS
+       VALGRIND_LIBS=$pkg_cv_VALGRIND_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
 fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
+
+$as_echo "#define VALGRIND_POOL 1" >>confdefs.h
+
+
+
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_tgetent" >&5
-$as_echo "$ac_cv_search_tgetent" >&6; }
-ac_res=$ac_cv_search_tgetent
-if test "$ac_res" != no; then
-  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-  READLINE_LIBS=$ac_cv_search_tgetent
-else
 
-               if test "$READLINE" = yes; then
-                       { { $as_echo "$as_me:$LINENO: error: termcap could not be found which is required for the
---enable-readline option (which is enabled by default).  Either disable readline
-support with --disable-readline or download and install termcap from:
-       ftp.gnu.org/gnu/termcap
-Note: if you are using precompiled packages you will also need the development
-  package as well (which may be called termcap-devel or something similar).
-Note: (n)curses also seems to work as a substitute for termcap.  This was
-  not found either - but you could try installing that as well." >&5
-$as_echo "$as_me: error: termcap could not be found which is required for the
---enable-readline option (which is enabled by default).  Either disable readline
-support with --disable-readline or download and install termcap from:
-       ftp.gnu.org/gnu/termcap
-Note: if you are using precompiled packages you will also need the development
-  package as well (which may be called termcap-devel or something similar).
-Note: (n)curses also seems to work as a substitute for termcap.  This was
-  not found either - but you could try installing that as well." >&2;}
-   { (exit 1); exit 1; }; }
-               fi
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use device-mapper" >&5
+$as_echo_n "checking whether to use device-mapper... " >&6; }
+# Check whether --enable-devmapper was given.
+if test "${enable_devmapper+set}" = set; then :
+  enableval=$enable_devmapper; DEVMAPPER=$enableval
 fi
 
-               { $as_echo "$as_me:$LINENO: checking for readline in -lreadline" >&5
-$as_echo_n "checking for readline in -lreadline... " >&6; }
-if test "${ac_cv_lib_readline_readline+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lreadline  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEVMAPPER" >&5
+$as_echo "$DEVMAPPER" >&6; }
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char readline ();
-int
-main ()
-{
-return readline ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_lib_readline_readline=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+if test x$DEVMAPPER = xyes; then
+
+$as_echo "#define DEVMAPPER_SUPPORT 1" >>confdefs.h
 
-       ac_cv_lib_readline_readline=no
 fi
 
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build LVMetaD" >&5
+$as_echo_n "checking whether to build LVMetaD... " >&6; }
+# Check whether --enable-lvmetad was given.
+if test "${enable_lvmetad+set}" = set; then :
+  enableval=$enable_lvmetad; LVMETAD=$enableval
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_readline_readline" >&5
-$as_echo "$ac_cv_lib_readline_readline" >&6; }
-if test "x$ac_cv_lib_readline_readline" = x""yes; then
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LVMETAD" >&5
+$as_echo "$LVMETAD" >&6; }
 
-cat >>confdefs.h <<\_ACEOF
-#define READLINE_SUPPORT 1
-_ACEOF
+BUILD_LVMETAD=$LVMETAD
 
-                               LIBS=$lvm_saved_libs
-               { $as_echo "$as_me:$LINENO: checking for rl_line_buffer in -lreadline" >&5
-$as_echo_n "checking for rl_line_buffer in -lreadline... " >&6; }
-if test "${ac_cv_lib_readline_rl_line_buffer+set}" = set; then
-  $as_echo_n "(cached) " >&6
+if test x$BUILD_LVMETAD = xyes; then
+
+$as_echo "#define LVMETAD_SUPPORT 1" >>confdefs.h
+
+
+
+# Check whether --with-lvmetad-pidfile was given.
+if test "${with_lvmetad_pidfile+set}" = set; then :
+  withval=$with_lvmetad_pidfile; LVMETAD_PIDFILE=$withval
 else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lreadline  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
+  LVMETAD_PIDFILE="$DEFAULT_PID_DIR/lvmetad.pid"
+fi
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char rl_line_buffer ();
-int
-main ()
-{
-return rl_line_buffer ();
-  ;
-  return 0;
-}
+
+cat >>confdefs.h <<_ACEOF
+#define LVMETAD_PIDFILE "$LVMETAD_PIDFILE"
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_lib_readline_rl_line_buffer=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
 
-       ac_cv_lib_readline_rl_line_buffer=no
 fi
 
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_readline_rl_line_buffer" >&5
-$as_echo "$ac_cv_lib_readline_rl_line_buffer" >&6; }
-if test "x$ac_cv_lib_readline_rl_line_buffer" = x""yes; then
-   READLINE_LIBS="-lreadline"
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable synchronisation with udev processing" >&5
+$as_echo_n "checking whether to enable synchronisation with udev processing... " >&6; }
+# Check whether --enable-udev_sync was given.
+if test "${enable_udev_sync+set}" = set; then :
+  enableval=$enable_udev_sync; UDEV_SYNC=$enableval
 else
+  UDEV_SYNC=no
+fi
 
-                         { $as_echo "$as_me:$LINENO: result: linking -lreadline with $READLINE_LIBS needed" >&5
-$as_echo "linking -lreadline with $READLINE_LIBS needed" >&6; }
-                         READLINE_LIBS="-lreadline $READLINE_LIBS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $UDEV_SYNC" >&5
+$as_echo "$UDEV_SYNC" >&6; }
 
-fi
+if test x$UDEV_SYNC = xyes; then
+               if  test x$PKGCONFIG_INIT != x1; then
+               pkg_config_init
+       fi
 
-else
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for UDEV" >&5
+$as_echo_n "checking for UDEV... " >&6; }
 
-               READLINE_LIBS=
-               if test "$READLINE" = yes; then
-                       { { $as_echo "$as_me:$LINENO: error: GNU Readline could not be found which is required for the
---enable-readline option (which is enabled by default).  Either disable readline
-support with --disable-readline or download and install readline from:
-       ftp.gnu.org/gnu/readline
-Note: if you are using precompiled packages you will also need the development
-package as well (which may be called readline-devel or something similar)." >&5
-$as_echo "$as_me: error: GNU Readline could not be found which is required for the
---enable-readline option (which is enabled by default).  Either disable readline
-support with --disable-readline or download and install readline from:
-       ftp.gnu.org/gnu/readline
-Note: if you are using precompiled packages you will also need the development
-package as well (which may be called readline-devel or something similar)." >&2;}
-   { (exit 1); exit 1; }; }
-               fi
+if test -n "$UDEV_CFLAGS"; then
+    pkg_cv_UDEV_CFLAGS="$UDEV_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libudev >= 143\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libudev >= 143") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_UDEV_CFLAGS=`$PKG_CONFIG --cflags "libudev >= 143" 2>/dev/null`
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$UDEV_LIBS"; then
+    pkg_cv_UDEV_LIBS="$UDEV_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libudev >= 143\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libudev >= 143") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_UDEV_LIBS=`$PKG_CONFIG --libs "libudev >= 143" 2>/dev/null`
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
 fi
 
-       LIBS="$READLINE_LIBS $lvm_saved_libs"
 
-for ac_func in rl_completion_matches
-do
-as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
-$as_echo_n "checking for $ac_func... " >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
+
+if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+               UDEV_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libudev >= 143" 2>&1`
+        else
+               UDEV_PKG_ERRORS=`$PKG_CONFIG --print-errors "libudev >= 143" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$UDEV_PKG_ERRORS" >&5
 
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
+       as_fn_error $? "Package requirements (libudev >= 143) were not met:
 
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
+$UDEV_PKG_ERRORS
 
-#undef $ac_func
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $ac_func ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub_$ac_func || defined __stub___$ac_func
-choke me
-#endif
+Alternatively, you may set the environment variables UDEV_CFLAGS
+and UDEV_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details." "$LINENO" 5
 
-int
-main ()
-{
-return $ac_func ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  eval "$as_ac_var=yes"
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "The pkg-config script could not be found or is too old.  Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
 
-       eval "$as_ac_var=no"
-fi
+Alternatively, you may set the environment variables UDEV_CFLAGS
+and UDEV_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
 
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-fi
-ac_res=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-as_val=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.
+See \`config.log' for more details" "$LINENO" 5; }
 
+else
+       UDEV_CFLAGS=$pkg_cv_UDEV_CFLAGS
+       UDEV_LIBS=$pkg_cv_UDEV_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+       UDEV_PC="libudev"
 fi
-done
 
-       LIBS=$lvm_saved_libs
+$as_echo "#define UDEV_SYNC_SUPPORT 1" >>confdefs.h
+
 fi
 
-################################################################################
-{ $as_echo "$as_me:$LINENO: checking whether to enable internationalisation" >&5
-$as_echo_n "checking whether to enable internationalisation... " >&6; }
-# Check whether --enable-nls was given.
-if test "${enable_nls+set}" = set; then
-  enableval=$enable_nls; INTL=$enableval
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable installation of udev rules required for synchronisation" >&5
+$as_echo_n "checking whether to enable installation of udev rules required for synchronisation... " >&6; }
+# Check whether --enable-udev_rules was given.
+if test "${enable_udev_rules+set}" = set; then :
+  enableval=$enable_udev_rules; UDEV_RULES=$enableval
 else
-  INTL=no
+  UDEV_RULES=$UDEV_SYNC
 fi
 
-{ $as_echo "$as_me:$LINENO: result: $INTL" >&5
-$as_echo "$INTL" >&6; }
-
-if test x$INTL = xyes; then
-# FIXME - Move this - can be device-mapper too
-       INTL_PACKAGE="lvm2"
-       # Extract the first word of "msgfmt", so it can be a program name with args.
-set dummy msgfmt; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_path_MSGFMT+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  case $MSGFMT in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
-    ac_cv_path_MSGFMT="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-IFS=$as_save_IFS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $UDEV_RULES" >&5
+$as_echo "$UDEV_RULES" >&6; }
 
-  ;;
-esac
-fi
-MSGFMT=$ac_cv_path_MSGFMT
-if test -n "$MSGFMT"; then
-  { $as_echo "$as_me:$LINENO: result: $MSGFMT" >&5
-$as_echo "$MSGFMT" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable executable path detection in udev rules" >&5
+$as_echo_n "checking whether to enable executable path detection in udev rules... " >&6; }
+# Check whether --enable-udev_rule_exec_detection was given.
+if test "${enable_udev_rule_exec_detection+set}" = set; then :
+  enableval=$enable_udev_rule_exec_detection; UDEV_RULE_EXEC_DETECTION=$enableval
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
+  UDEV_RULE_EXEC_DETECTION=no
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $UDEV_RULE_EXEC_DETECTION" >&5
+$as_echo "$UDEV_RULE_EXEC_DETECTION" >&6; }
 
-       if [ "x$MSGFMT" == x ];
-               then  { { $as_echo "$as_me:$LINENO: error: msgfmt not found in path $PATH
-               " >&5
-$as_echo "$as_me: error: msgfmt not found in path $PATH
-               " >&2;}
-   { (exit 1); exit 1; }; }
-       fi;
-
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether udev supports built-in blkid" >&5
+$as_echo_n "checking whether udev supports built-in blkid... " >&6; }
+test x$PKGCONFIG_INIT != x1 && pkg_config_init
+if $($PKG_CONFIG --atleast-version=176 libudev); then
+       UDEV_HAS_BUILTIN_BLKID=yes
+else
+       UDEV_HAS_BUILTIN_BLKID=no
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $UDEV_HAS_BUILTIN_BLKID" >&5
+$as_echo "$UDEV_HAS_BUILTIN_BLKID" >&6; }
 
-# Check whether --with-localedir was given.
-if test "${with_localedir+set}" = set; then
-  withval=$with_localedir; LOCALEDIR=$withval
+################################################################################
+# Check whether --enable-compat was given.
+if test "${enable_compat+set}" = set; then :
+  enableval=$enable_compat; DM_COMPAT=$enableval
 else
-  LOCALEDIR='${prefix}/share/locale'
+  DM_COMPAT=no
 fi
 
+
+if test x$DM_COMPAT = xyes; then
+       as_fn_error $? "--enable-compat is not currently supported.
+Since device-mapper version 1.02.66, only one version (4) of the device-mapper
+ioctl protocol is supported.
+       " "$LINENO" 5
 fi
 
 ################################################################################
-
-# Check whether --with-confdir was given.
-if test "${with_confdir+set}" = set; then
-  withval=$with_confdir; CONFDIR=$withval
+# Check whether --enable-units-compat was given.
+if test "${enable_units_compat+set}" = set; then :
+  enableval=$enable_units_compat; UNITS_COMPAT=$enableval
 else
-  CONFDIR="/etc"
+  UNITS_COMPAT=no
 fi
 
 
+if test x$UNITS_COMPAT = xyes; then
+
+$as_echo "#define DEFAULT_SI_UNIT_CONSISTENCY 0" >>confdefs.h
 
-# Check whether --with-staticdir was given.
-if test "${with_staticdir+set}" = set; then
-  withval=$with_staticdir; STATICDIR=$withval
-else
-  STATICDIR='${exec_prefix}/sbin'
 fi
 
+################################################################################
+# Check whether --enable-ioctl was given.
+if test "${enable_ioctl+set}" = set; then :
+  enableval=$enable_ioctl; DM_IOCTLS=$enableval
+fi
 
 
-# Check whether --with-usrlibdir was given.
-if test "${with_usrlibdir+set}" = set; then
-  withval=$with_usrlibdir; usrlibdir=$withval
-else
-  usrlibdir='${prefix}/lib'
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable O_DIRECT" >&5
+$as_echo_n "checking whether to enable O_DIRECT... " >&6; }
+# Check whether --enable-o_direct was given.
+if test "${enable_o_direct+set}" = set; then :
+  enableval=$enable_o_direct; ODIRECT=$enableval
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ODIRECT" >&5
+$as_echo "$ODIRECT" >&6; }
 
+if test x$ODIRECT = xyes; then
 
-# Check whether --with-usrsbindir was given.
-if test "${with_usrsbindir+set}" = set; then
-  withval=$with_usrsbindir; usrsbindir=$withval
-else
-  usrsbindir='${prefix}/sbin'
-fi
+$as_echo "#define O_DIRECT_SUPPORT 1" >>confdefs.h
 
+fi
 
 ################################################################################
-
-# Check whether --with-udev_prefix was given.
-if test "${with_udev_prefix+set}" = set; then
-  withval=$with_udev_prefix; udev_prefix=$withval
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build liblvm2app.so application library" >&5
+$as_echo_n "checking whether to build liblvm2app.so application library... " >&6; }
+# Check whether --enable-applib was given.
+if test "${enable_applib+set}" = set; then :
+  enableval=$enable_applib; APPLIB=$enableval
 else
-  udev_prefix='${exec_prefix}'
+  APPLIB=no
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $APPLIB" >&5
+$as_echo "$APPLIB" >&6; }
 
+test x$APPLIB = xyes \
+  && LVM2APP_LIB=-llvm2app \
+  || LVM2APP_LIB=
 
-# Check whether --with-udevdir was given.
-if test "${with_udevdir+set}" = set; then
-  withval=$with_udevdir; udevdir=$withval
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile liblvm2cmd.so" >&5
+$as_echo_n "checking whether to compile liblvm2cmd.so... " >&6; }
+# Check whether --enable-cmdlib was given.
+if test "${enable_cmdlib+set}" = set; then :
+  enableval=$enable_cmdlib; CMDLIB=$enableval
 else
-  udevdir='${udev_prefix}/lib/udev/rules.d'
+  CMDLIB=no
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CMDLIB" >&5
+$as_echo "$CMDLIB" >&6; }
+
+test x$CMDLIB = xyes \
+  && LVM2CMD_LIB=-llvm2cmd \
+  || LVM2CMD_LIB=
 
 ################################################################################
-if test x$READLINE = xyes; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build Python wrapper for liblvm2app.so" >&5
+$as_echo_n "checking whether to build Python wrapper for liblvm2app.so... " >&6; }
+# Check whether --enable-python_bindings was given.
+if test "${enable_python_bindings+set}" = set; then :
+  enableval=$enable_python_bindings; PYTHON_BINDINGS=$enableval
+else
+  PYTHON_BINDINGS=no
+fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_BINDINGS" >&5
+$as_echo "$PYTHON_BINDINGS" >&6; }
 
-for ac_header in readline/readline.h readline/history.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+if test x$PYTHON_BINDINGS = xyes; then
+       if test x$APPLIB != xyes; then
+               as_fn_error $? "--enable-python_bindings requires --enable-applib
+               " "$LINENO" 5
+       fi
+
+       # Extract the first word of "python", so it can be a program name with args.
+set dummy python; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_path_PYTHON+set}" = set; then :
   $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
+  case $PYTHON in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PYTHON="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_PYTHON" && ac_cv_path_PYTHON="notfound"
+  ;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
+fi
+PYTHON=$ac_cv_path_PYTHON
+if test -n "$PYTHON"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON" >&5
+$as_echo "$PYTHON" >&6; }
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_header_compiler=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
+       if test x$PYTHON == xnotfound; then
+               as_fn_error $? "python is required for --enable-python_bindings but cannot be found
+               " "$LINENO" 5
+       fi
+
+       # Extract the first word of "python-config", so it can be a program name with args.
+set dummy python-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_path_PYTHON_CONFIG+set}" = set; then :
+  $as_echo_n "(cached) " >&6
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  case $PYTHON_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PYTHON_CONFIG="$PYTHON_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PYTHON_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
-  ac_header_preproc=no
+  test -z "$ac_cv_path_PYTHON_CONFIG" && ac_cv_path_PYTHON_CONFIG="notfound"
+  ;;
+esac
+fi
+PYTHON_CONFIG=$ac_cv_path_PYTHON_CONFIG
+if test -n "$PYTHON_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_CONFIG" >&5
+$as_echo "$PYTHON_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
 
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+       if test x$PYTHON_CONFIG == xnotfound; then
+               as_fn_error $? "python headers are required for --enable-python_bindings but cannot be found
+               " "$LINENO" 5
+       fi
+
+       PYTHON_INCDIRS=`$PYTHON_CONFIG --includes`
+       PYTHON_LIBDIRS=`$PYTHON_CONFIG --libs`
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  eval "$as_ac_Header=\$ac_header_preproc"
 fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 
+################################################################################
+# Check whether --enable-pkgconfig was given.
+if test "${enable_pkgconfig+set}" = set; then :
+  enableval=$enable_pkgconfig; PKGCONFIG=$enableval
+else
+  PKGCONFIG=no
 fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
 
+
+################################################################################
+# Check whether --enable-write_install was given.
+if test "${enable_write_install+set}" = set; then :
+  enableval=$enable_write_install; WRITE_INSTALL=$enableval
 else
-  { { $as_echo "$as_me:$LINENO: error: bailing out" >&5
-$as_echo "$as_me: error: bailing out" >&2;}
-   { (exit 1); exit 1; }; }
+  WRITE_INSTALL=no
 fi
 
-done
 
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to install fsadm" >&5
+$as_echo_n "checking whether to install fsadm... " >&6; }
+# Check whether --enable-fsadm was given.
+if test "${enable_fsadm+set}" = set; then :
+  enableval=$enable_fsadm; FSADM=$enableval
 fi
 
-if test x$CLVMD != xnone; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $FSADM" >&5
+$as_echo "$FSADM" >&6; }
 
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to install blkdeactivate" >&5
+$as_echo_n "checking whether to install blkdeactivate... " >&6; }
+# Check whether --enable-blkdeactivate was given.
+if test "${enable_blkdeactivate+set}" = set; then :
+  enableval=$enable_blkdeactivate; BLKDEACTIVATE=$enableval
+fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $BLKDEACTIVATE" >&5
+$as_echo "$BLKDEACTIVATE" >&6; }
+
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use dmeventd" >&5
+$as_echo_n "checking whether to use dmeventd... " >&6; }
+# Check whether --enable-dmeventd was given.
+if test "${enable_dmeventd+set}" = set; then :
+  enableval=$enable_dmeventd; DMEVENTD=$enableval
+fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DMEVENTD" >&5
+$as_echo "$DMEVENTD" >&6; }
 
+BUILD_DMEVENTD=$DMEVENTD
 
+if test x$DMEVENTD = xyes; then
+   if test x$MIRRORS != xinternal; then
+      as_fn_error $? "--enable-dmeventd currently requires --with-mirrors=internal
+      " "$LINENO" 5
+   fi
+   if test x$CMDLIB = xno; then
+      as_fn_error $? "--enable-dmeventd requires --enable-cmdlib to be used as well
+      " "$LINENO" 5
+   fi
+fi
 
+if test x$DMEVENTD = xyes; then
 
+$as_echo "#define DMEVENTD 1" >>confdefs.h
 
+fi
 
+################################################################################
 
-for ac_header in mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for getline in -lc" >&5
+$as_echo_n "checking for getline in -lc... " >&6; }
+if test "${ac_cv_lib_c_getline+set}" = set; then :
   $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char getline ();
+int
+main ()
+{
+return getline ();
+  ;
+  return 0;
+}
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_c_getline=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_header_compiler=no
+  ac_cv_lib_c_getline=no
 fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_getline" >&5
+$as_echo "$ac_cv_lib_c_getline" >&6; }
+if test "x$ac_cv_lib_c_getline" = x""yes; then :
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+$as_echo "#define HAVE_GETLINE 1" >>confdefs.h
 
-  ac_header_preproc=no
 fi
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
 
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+################################################################################
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for canonicalize_file_name in -lc" >&5
+$as_echo_n "checking for canonicalize_file_name in -lc... " >&6; }
+if test "${ac_cv_lib_c_canonicalize_file_name+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  eval "$as_ac_Header=\$ac_header_preproc"
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
 
-fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char canonicalize_file_name ();
+int
+main ()
+{
+return canonicalize_file_name ();
+  ;
+  return 0;
+}
 _ACEOF
-
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_c_canonicalize_file_name=yes
 else
-  { { $as_echo "$as_me:$LINENO: error: bailing out" >&5
-$as_echo "$as_me: error: bailing out" >&2;}
-   { (exit 1); exit 1; }; }
+  ac_cv_lib_c_canonicalize_file_name=no
 fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_canonicalize_file_name" >&5
+$as_echo "$ac_cv_lib_c_canonicalize_file_name" >&6; }
+if test "x$ac_cv_lib_c_canonicalize_file_name" = x""yes; then :
 
-done
-
-
+$as_echo "#define HAVE_CANONICALIZE_FILE_NAME 1" >>confdefs.h
 
+fi
 
 
+################################################################################
+if [ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ];
+ then  exec_prefix="";
+fi;
 
-for ac_func in dup2 getmntent memmove select socket
-do
-as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
-$as_echo_n "checking for $ac_func... " >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef $ac_func
 
 /* Override any GCC internal prototype to avoid an error.
    Use char because int might match the return type of a GCC
@@ -16714,86 +9497,59 @@ cat >>conftest.$ac_ext <<_ACEOF
 #ifdef __cplusplus
 extern "C"
 #endif
-char $ac_func ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub_$ac_func || defined __stub___$ac_func
-choke me
-#endif
-
+char dlopen ();
 int
 main ()
 {
-return $ac_func ();
+return dlopen ();
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  eval "$as_ac_var=yes"
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dl_dlopen=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       eval "$as_ac_var=no"
+  ac_cv_lib_dl_dlopen=no
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
 fi
-ac_res=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-as_val=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = x""yes; then :
+
 
+$as_echo "#define HAVE_LIBDL 1" >>confdefs.h
+
+       DL_LIBS="-ldl"
+       HAVE_LIBDL=yes
 else
-  { { $as_echo "$as_me:$LINENO: error: bailing out" >&5
-$as_echo "$as_me: error: bailing out" >&2;}
-   { (exit 1); exit 1; }; }
+
+       DL_LIBS=
+       HAVE_LIBDL=no
 fi
-done
 
-       # getmntent is in the standard C library on UNICOS, in -lsun on Irix 4,
-# -lseq on Dynix/PTX, -lgen on Unixware.
-{ $as_echo "$as_me:$LINENO: checking for library containing getmntent" >&5
-$as_echo_n "checking for library containing getmntent... " >&6; }
-if test "${ac_cv_search_getmntent+set}" = set; then
+
+################################################################################
+if [ \( "x$LVM1" = xshared -o "x$POOL" = xshared -o "x$CLUSTER" = xshared \
+      -o "x$SNAPSHOTS" = xshared -o "x$MIRRORS" = xshared \
+      -o "x$RAID" = xshared \
+      \) -a "x$STATIC_LINK" = xyes ];
+ then  as_fn_error $? "Features cannot be 'shared' when building statically
+" "$LINENO" 5
+fi
+
+################################################################################
+if [ "$DMEVENTD" = yes -o "$CLVMD" != none ] ; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_lock in -lpthread" >&5
+$as_echo_n "checking for pthread_mutex_lock in -lpthread... " >&6; }
+if test "${ac_cv_lib_pthread_pthread_mutex_lock+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  ac_func_search_save_LIBS=$LIBS
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 /* Override any GCC internal prototype to avoid an error.
@@ -16802,503 +9558,367 @@ cat >>conftest.$ac_ext <<_ACEOF
 #ifdef __cplusplus
 extern "C"
 #endif
-char getmntent ();
+char pthread_mutex_lock ();
 int
 main ()
 {
-return getmntent ();
+return pthread_mutex_lock ();
   ;
   return 0;
 }
 _ACEOF
-for ac_lib in '' sun seq gen; do
-  if test -z "$ac_lib"; then
-    ac_res="none required"
-  else
-    ac_res=-l$ac_lib
-    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
-  fi
-  rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_search_getmntent=$ac_res
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_pthread_pthread_mutex_lock=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
+  ac_cv_lib_pthread_pthread_mutex_lock=no
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext
-  if test "${ac_cv_search_getmntent+set}" = set; then
-  break
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
 fi
-done
-if test "${ac_cv_search_getmntent+set}" = set; then
-  :
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_mutex_lock" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_mutex_lock" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_mutex_lock" = x""yes; then :
+  PTHREAD_LIBS="-lpthread"
 else
-  ac_cv_search_getmntent=no
+  hard_bailout
 fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
+
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_getmntent" >&5
-$as_echo "$ac_cv_search_getmntent" >&6; }
-ac_res=$ac_cv_search_getmntent
-if test "$ac_res" != no; then
-  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-  ac_cv_func_getmntent=yes
 
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_GETMNTENT 1
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable selinux support" >&5
+$as_echo_n "checking whether to enable selinux support... " >&6; }
+# Check whether --enable-selinux was given.
+if test "${enable_selinux+set}" = set; then :
+  enableval=$enable_selinux; SELINUX=$enableval
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $SELINUX" >&5
+$as_echo "$SELINUX" >&6; }
+
+################################################################################
+if test x$SELINUX = xyes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sepol_check_context in -lsepol" >&5
+$as_echo_n "checking for sepol_check_context in -lsepol... " >&6; }
+if test "${ac_cv_lib_sepol_sepol_check_context+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsepol  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char sepol_check_context ();
+int
+main ()
+{
+return sepol_check_context ();
+  ;
+  return 0;
+}
 _ACEOF
-
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_sepol_sepol_check_context=yes
 else
-  ac_cv_func_getmntent=no
+  ac_cv_lib_sepol_sepol_check_context=no
 fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sepol_sepol_check_context" >&5
+$as_echo "$ac_cv_lib_sepol_sepol_check_context" >&6; }
+if test "x$ac_cv_lib_sepol_sepol_check_context" = x""yes; then :
+
 
+$as_echo "#define HAVE_SEPOL 1" >>confdefs.h
 
+               SELINUX_LIBS="-lsepol"
+fi
 
 
-for ac_header in sys/select.h sys/socket.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for is_selinux_enabled in -lselinux" >&5
+$as_echo_n "checking for is_selinux_enabled in -lselinux... " >&6; }
+if test "${ac_cv_lib_selinux_is_selinux_enabled+set}" = set; then :
   $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lselinux  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char is_selinux_enabled ();
+int
+main ()
+{
+return is_selinux_enabled ();
+  ;
+  return 0;
+}
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_selinux_is_selinux_enabled=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  ac_cv_lib_selinux_is_selinux_enabled=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_selinux_is_selinux_enabled" >&5
+$as_echo "$ac_cv_lib_selinux_is_selinux_enabled" >&6; }
+if test "x$ac_cv_lib_selinux_is_selinux_enabled" = x""yes; then :
+
+               for ac_header in selinux/selinux.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "selinux/selinux.h" "ac_cv_header_selinux_selinux_h" "$ac_includes_default"
+if test "x$ac_cv_header_selinux_selinux_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SELINUX_SELINUX_H 1
+_ACEOF
 
-       ac_header_compiler=no
+else
+  hard_bailout
 fi
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
+done
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
+               for ac_header in selinux/label.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "selinux/label.h" "ac_cv_header_selinux_label_h" "$ac_includes_default"
+if test "x$ac_cv_header_selinux_label_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SELINUX_LABEL_H 1
 _ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
 
-  ac_header_preproc=no
 fi
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
+done
 
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
+$as_echo "#define HAVE_SELINUX 1" >>confdefs.h
+
+               SELINUX_LIBS="-lselinux $SELINUX_LIBS"
+               SELINUX_PC="libselinux"
+               HAVE_SELINUX=yes
 else
-  eval "$as_ac_Header=\$ac_header_preproc"
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 
+               { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Disabling selinux" >&5
+$as_echo "$as_me: WARNING: Disabling selinux" >&2;}
+               SELINUX_LIBS=
+               SELINUX_PC=
+               HAVE_SELINUX=no
 fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
 
 fi
 
-done
-
-{ $as_echo "$as_me:$LINENO: checking types of arguments for select" >&5
-$as_echo_n "checking types of arguments for select... " >&6; }
-if test "${ac_cv_func_select_args+set}" = set; then
+################################################################################
+if test x$REALTIME = xyes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5
+$as_echo_n "checking for clock_gettime in -lrt... " >&6; }
+if test "${ac_cv_lib_rt_clock_gettime+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  for ac_arg234 in 'fd_set *' 'int *' 'void *'; do
- for ac_arg1 in 'int' 'size_t' 'unsigned long int' 'unsigned int'; do
-  for ac_arg5 in 'struct timeval *' 'const struct timeval *'; do
-   cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lrt  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_includes_default
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
 
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char clock_gettime ();
 int
 main ()
 {
-extern int select ($ac_arg1,
-                                           $ac_arg234, $ac_arg234, $ac_arg234,
-                                           $ac_arg5);
+return clock_gettime ();
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_func_select_args="$ac_arg1,$ac_arg234,$ac_arg5"; break 3
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_rt_clock_gettime=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
+  ac_cv_lib_rt_clock_gettime=no
 fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-  done
- done
-done
-# Provide a safe default value.
-: ${ac_cv_func_select_args='int,int *,struct timeval *'}
-
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5
+$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; }
+if test "x$ac_cv_lib_rt_clock_gettime" = x""yes; then :
+  HAVE_REALTIME=yes
+else
+  HAVE_REALTIME=no
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_select_args" >&5
-$as_echo "$ac_cv_func_select_args" >&6; }
-ac_save_IFS=$IFS; IFS=','
-set dummy `echo "$ac_cv_func_select_args" | sed 's/\*/\*/g'`
-IFS=$ac_save_IFS
-shift
 
-cat >>confdefs.h <<_ACEOF
-#define SELECT_TYPE_ARG1 $1
-_ACEOF
 
+       if test x$HAVE_REALTIME = xyes; then
 
-cat >>confdefs.h <<_ACEOF
-#define SELECT_TYPE_ARG234 ($2)
-_ACEOF
+$as_echo "#define HAVE_REALTIME 1" >>confdefs.h
 
+               LIBS="-lrt $LIBS"
+       else
+               { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Disabling realtime clock" >&5
+$as_echo "$as_me: WARNING: Disabling realtime clock" >&2;}
+       fi
+fi
 
-cat >>confdefs.h <<_ACEOF
-#define SELECT_TYPE_ARG5 ($3)
+################################################################################
+for ac_header in getopt.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "getopt.h" "ac_cv_header_getopt_h" "$ac_includes_default"
+if test "x$ac_cv_header_getopt_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_GETOPT_H 1
 _ACEOF
 
-rm -f conftest*
+$as_echo "#define HAVE_GETOPTLONG 1" >>confdefs.h
 
 fi
 
-if test x$CLUSTER != xnone; then
+done
 
 
-for ac_header in sys/socket.h sys/un.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+################################################################################
+if test x$READLINE != xno; then
+       lvm_saved_libs=$LIBS
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing tgetent" >&5
+$as_echo_n "checking for library containing tgetent... " >&6; }
+if test "${ac_cv_search_tgetent+set}" = set; then :
   $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
 
-       ac_header_compiler=no
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char tgetent ();
+int
+main ()
+{
+return tgetent ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' tinfo ncurses curses termcap termlib; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_tgetent=$ac_res
 fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if test "${ac_cv_search_tgetent+set}" = set; then :
+  break
+fi
+done
+if test "${ac_cv_search_tgetent+set}" = set; then :
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  ac_cv_search_tgetent=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_tgetent" >&5
+$as_echo "$ac_cv_search_tgetent" >&6; }
+ac_res=$ac_cv_search_tgetent
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+  READLINE_LIBS=$ac_cv_search_tgetent
+else
 
-  ac_header_preproc=no
+               if test "$READLINE" = yes; then
+                       as_fn_error $? "termcap could not be found which is required for the
+--enable-readline option (which is enabled by default).  Either disable readline
+support with --disable-readline or download and install termcap from:
+       ftp.gnu.org/gnu/termcap
+Note: if you are using precompiled packages you will also need the development
+  package as well (which may be called termcap-devel or something similar).
+Note: (n)curses also seems to work as a substitute for termcap.  This was
+  not found either - but you could try installing that as well." "$LINENO" 5
+               fi
 fi
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
-
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+               { $as_echo "$as_me:${as_lineno-$LINENO}: checking for readline in -lreadline" >&5
+$as_echo_n "checking for readline in -lreadline... " >&6; }
+if test "${ac_cv_lib_readline_readline+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  eval "$as_ac_Header=\$ac_header_preproc"
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lreadline  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
 
-fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char readline ();
+int
+main ()
+{
+return readline ();
+  ;
+  return 0;
+}
 _ACEOF
-
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_readline_readline=yes
 else
-  { { $as_echo "$as_me:$LINENO: error: bailing out" >&5
-$as_echo "$as_me: error: bailing out" >&2;}
-   { (exit 1); exit 1; }; }
+  ac_cv_lib_readline_readline=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_readline" >&5
+$as_echo "$ac_cv_lib_readline_readline" >&6; }
+if test "x$ac_cv_lib_readline_readline" = x""yes; then :
 
-done
 
+$as_echo "#define READLINE_SUPPORT 1" >>confdefs.h
 
-for ac_func in socket
-do
-as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
-$as_echo_n "checking for $ac_func... " >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+                               LIBS=$lvm_saved_libs
+               { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_line_buffer in -lreadline" >&5
+$as_echo_n "checking for rl_line_buffer in -lreadline... " >&6; }
+if test "${ac_cv_lib_readline_rl_line_buffer+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lreadline  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef $ac_func
 
 /* Override any GCC internal prototype to avoid an error.
    Use char because int might match the return type of a GCC
@@ -17306,682 +9926,507 @@ cat >>conftest.$ac_ext <<_ACEOF
 #ifdef __cplusplus
 extern "C"
 #endif
-char $ac_func ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub_$ac_func || defined __stub___$ac_func
-choke me
-#endif
-
+char rl_line_buffer ();
 int
 main ()
 {
-return $ac_func ();
+return rl_line_buffer ();
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  eval "$as_ac_var=yes"
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_readline_rl_line_buffer=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  ac_cv_lib_readline_rl_line_buffer=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_line_buffer" >&5
+$as_echo "$ac_cv_lib_readline_rl_line_buffer" >&6; }
+if test "x$ac_cv_lib_readline_rl_line_buffer" = x""yes; then :
+   READLINE_LIBS="-lreadline"
+else
+
+                         { $as_echo "$as_me:${as_lineno-$LINENO}: result: linking -lreadline with $READLINE_LIBS needed" >&5
+$as_echo "linking -lreadline with $READLINE_LIBS needed" >&6; }
+                         READLINE_LIBS="-lreadline $READLINE_LIBS"
 
-       eval "$as_ac_var=no"
 fi
 
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+else
+
+               READLINE_LIBS=
+               if test "$READLINE" = yes; then
+                       as_fn_error $? "GNU Readline could not be found which is required for the
+--enable-readline option (which is enabled by default).  Either disable readline
+support with --disable-readline or download and install readline from:
+       ftp.gnu.org/gnu/readline
+Note: if you are using precompiled packages you will also need the development
+package as well (which may be called readline-devel or something similar)." "$LINENO" 5
+               fi
 fi
-ac_res=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-as_val=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
+
+       LIBS="$READLINE_LIBS $lvm_saved_libs"
+       for ac_func in rl_completion_matches
+do :
+  ac_fn_c_check_func "$LINENO" "rl_completion_matches" "ac_cv_func_rl_completion_matches"
+if test "x$ac_cv_func_rl_completion_matches" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+#define HAVE_RL_COMPLETION_MATCHES 1
 _ACEOF
 
-else
-  { { $as_echo "$as_me:$LINENO: error: bailing out" >&5
-$as_echo "$as_me: error: bailing out" >&2;}
-   { (exit 1); exit 1; }; }
 fi
 done
 
+       LIBS=$lvm_saved_libs
 fi
 
-if test x$DMEVENTD = xyes; then
+################################################################################
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable internationalisation" >&5
+$as_echo_n "checking whether to enable internationalisation... " >&6; }
+# Check whether --enable-nls was given.
+if test "${enable_nls+set}" = set; then :
+  enableval=$enable_nls; INTL=$enableval
+else
+  INTL=no
+fi
 
-for ac_header in arpa/inet.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INTL" >&5
+$as_echo "$INTL" >&6; }
+
+if test x$INTL = xyes; then
+# FIXME - Move this - can be device-mapper too
+       INTL_PACKAGE="lvm2"
+       # Extract the first word of "msgfmt", so it can be a program name with args.
+set dummy msgfmt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_path_MSGFMT+set}" = set; then :
   $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
+  case $MSGFMT in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_MSGFMT="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
+fi
+MSGFMT=$ac_cv_path_MSGFMT
+if test -n "$MSGFMT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGFMT" >&5
+$as_echo "$MSGFMT" >&6; }
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+       if [ "x$MSGFMT" == x ];
+               then  as_fn_error $? "msgfmt not found in path $PATH
+               " "$LINENO" 5
+       fi;
 
-       ac_header_compiler=no
+
+# Check whether --with-localedir was given.
+if test "${with_localedir+set}" = set; then :
+  withval=$with_localedir; LOCALEDIR=$withval
+else
+  LOCALEDIR='${prefix}/share/locale'
 fi
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
+fi
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
+################################################################################
+
+# Check whether --with-confdir was given.
+if test "${with_confdir+set}" = set; then :
+  withval=$with_confdir; CONFDIR=$withval
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  CONFDIR="/etc"
+fi
 
-  ac_header_preproc=no
+
+
+# Check whether --with-staticdir was given.
+if test "${with_staticdir+set}" = set; then :
+  withval=$with_staticdir; STATICDIR=$withval
+else
+  STATICDIR='${exec_prefix}/sbin'
 fi
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
 
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
+# Check whether --with-usrlibdir was given.
+if test "${with_usrlibdir+set}" = set; then :
+  withval=$with_usrlibdir; usrlibdir=$withval
+else
+  usrlibdir='${prefix}/lib'
+fi
+
+
+
+# Check whether --with-usrsbindir was given.
+if test "${with_usrsbindir+set}" = set; then :
+  withval=$with_usrsbindir; usrsbindir=$withval
+else
+  usrsbindir='${prefix}/sbin'
+fi
+
+
+################################################################################
+
+# Check whether --with-udev_prefix was given.
+if test "${with_udev_prefix+set}" = set; then :
+  withval=$with_udev_prefix; udev_prefix=$withval
+else
+  udev_prefix='${exec_prefix}'
+fi
+
+
+
+# Check whether --with-udevdir was given.
+if test "${with_udevdir+set}" = set; then :
+  withval=$with_udevdir; udevdir=$withval
+else
+  udevdir='${udev_prefix}/lib/udev/rules.d'
+fi
+
+
+################################################################################
+
+# Check whether --with-systemdsystemunitdir was given.
+if test "${with_systemdsystemunitdir+set}" = set; then :
+  withval=$with_systemdsystemunitdir; systemdsystemunitdir=$withval
+else
+           test x$PKGCONFIG_INIT != x1 && pkg_config_init
+           pkg_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)
+fi
+
+
+if test -n "$pkg_systemdsystemunitdir"; then
+           systemdsystemunitdir=$pkg_systemdsystemunitdir;
+fi
+
+if test -z "$systemdsystemunitdir"; then
+           systemdsystemunitdir='${exec_prefix}/lib/systemd/system';
+fi
+
+systemdutildir=$($PKG_CONFIG --variable=systemdutildir systemd)
+if test -z "$systemdutildir"; then
+           systemdutildir='${exec_prefix}/lib/systemd';
+fi
+################################################################################
+
+# Check whether --with-tmpfilesdir was given.
+if test "${with_tmpfilesdir+set}" = set; then :
+  withval=$with_tmpfilesdir; tmpfilesdir=$withval
 else
-  eval "$as_ac_Header=\$ac_header_preproc"
+  tmpfilesdir='${prefix}/lib/tmpfiles.d'
 fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 
-fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
+################################################################################
+if test x$READLINE = xyes; then
+       for ac_header in readline/readline.h readline/history.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
   cat >>confdefs.h <<_ACEOF
 #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
 _ACEOF
 
 else
-  { { $as_echo "$as_me:$LINENO: error: bailing out" >&5
-$as_echo "$as_me: error: bailing out" >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error $? "bailing out" "$LINENO" 5
 fi
 
 done
 
 fi
 
-if test x$HAVE_LIBDL = xyes; then
-
-for ac_header in dlfcn.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
+if test x$CLVMD != xnone; then
+       for ac_header in mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
 
-       ac_header_compiler=no
+else
+  as_fn_error $? "bailing out" "$LINENO" 5
 fi
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
+done
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
+       for ac_func in dup2 getmntent memmove select socket
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
 _ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
 
-  ac_header_preproc=no
+else
+  as_fn_error $? "bailing out" "$LINENO" 5
 fi
+done
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
+       # getmntent is in the standard C library on UNICOS, in -lsun on Irix 4,
+# -lseq on Dynix/PTX, -lgen on Unixware.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing getmntent" >&5
+$as_echo_n "checking for library containing getmntent... " >&6; }
+if test "${ac_cv_search_getmntent+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
 
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char getmntent ();
+int
+main ()
+{
+return getmntent ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' sun seq gen; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_getmntent=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if test "${ac_cv_search_getmntent+set}" = set; then :
+  break
+fi
+done
+if test "${ac_cv_search_getmntent+set}" = set; then :
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
 else
-  eval "$as_ac_Header=\$ac_header_preproc"
+  ac_cv_search_getmntent=no
 fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_getmntent" >&5
+$as_echo "$ac_cv_search_getmntent" >&6; }
+ac_res=$ac_cv_search_getmntent
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+  ac_cv_func_getmntent=yes
+
+$as_echo "#define HAVE_GETMNTENT 1" >>confdefs.h
 
+else
+  ac_cv_func_getmntent=no
 fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
+
+
+       for ac_header in sys/select.h sys/socket.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
   cat >>confdefs.h <<_ACEOF
 #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
 _ACEOF
 
-else
-  { { $as_echo "$as_me:$LINENO: error: bailing out" >&5
-$as_echo "$as_me: error: bailing out" >&2;}
-   { (exit 1); exit 1; }; }
 fi
 
 done
 
-fi
-
-if test x$INTL = xyes; then
-
-for ac_header in libintl.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking types of arguments for select" >&5
+$as_echo_n "checking types of arguments for select... " >&6; }
+if test "${ac_cv_func_select_args+set}" = set; then :
   $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  for ac_arg234 in 'fd_set *' 'int *' 'void *'; do
+ for ac_arg1 in 'int' 'size_t' 'unsigned long int' 'unsigned int'; do
+  for ac_arg5 in 'struct timeval *' 'const struct timeval *'; do
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 $ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
 
-       ac_header_compiler=no
+int
+main ()
+{
+extern int select ($ac_arg1,
+                                           $ac_arg234, $ac_arg234, $ac_arg234,
+                                           $ac_arg5);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_func_select_args="$ac_arg1,$ac_arg234,$ac_arg5"; break 3
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
+  done
+ done
+done
+# Provide a safe default value.
+: ${ac_cv_func_select_args='int,int *,struct timeval *'}
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_select_args" >&5
+$as_echo "$ac_cv_func_select_args" >&6; }
+ac_save_IFS=$IFS; IFS=','
+set dummy `echo "$ac_cv_func_select_args" | sed 's/\*/\*/g'`
+IFS=$ac_save_IFS
+shift
+
+cat >>confdefs.h <<_ACEOF
+#define SELECT_TYPE_ARG1 $1
 _ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
+
+
+cat >>confdefs.h <<_ACEOF
+#define SELECT_TYPE_ARG234 ($2)
 _ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
 
-  ac_header_preproc=no
-fi
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
+cat >>confdefs.h <<_ACEOF
+#define SELECT_TYPE_ARG5 ($3)
+_ACEOF
 
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+rm -f conftest*
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  eval "$as_ac_Header=\$ac_header_preproc"
 fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
 
-fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
+if test x$CLUSTER != xnone; then
+       for ac_header in sys/socket.h sys/un.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
   cat >>confdefs.h <<_ACEOF
 #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
 _ACEOF
 
 else
-  { { $as_echo "$as_me:$LINENO: error: bailing out" >&5
-$as_echo "$as_me: error: bailing out" >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error $? "bailing out" "$LINENO" 5
 fi
 
 done
 
-fi
-
-if test x$UDEV_SYNC = xyes; then
-
-
-for ac_header in sys/ipc.h sys/sem.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
+       for ac_func in socket
+do :
+  ac_fn_c_check_func "$LINENO" "socket" "ac_cv_func_socket"
+if test "x$ac_cv_func_socket" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SOCKET 1
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
 
-       ac_header_compiler=no
+else
+  as_fn_error $? "bailing out" "$LINENO" 5
 fi
+done
 
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
+fi
+
+if test x$DMEVENTD = xyes; then
+       for ac_header in arpa/inet.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "arpa/inet.h" "ac_cv_header_arpa_inet_h" "$ac_includes_default"
+if test "x$ac_cv_header_arpa_inet_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_ARPA_INET_H 1
+_ACEOF
 
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  as_fn_error $? "bailing out" "$LINENO" 5
+fi
+
+done
 
-  ac_header_preproc=no
 fi
 
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
+if test x$HAVE_LIBDL = xyes; then
+       for ac_header in dlfcn.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default"
+if test "x$ac_cv_header_dlfcn_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
 
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+else
+  as_fn_error $? "bailing out" "$LINENO" 5
+fi
+
+done
+
+fi
+
+if test x$INTL = xyes; then
+       for ac_header in libintl.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "libintl.h" "ac_cv_header_libintl_h" "$ac_includes_default"
+if test "x$ac_cv_header_libintl_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBINTL_H 1
+_ACEOF
 
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
 else
-  eval "$as_ac_Header=\$ac_header_preproc"
+  as_fn_error $? "bailing out" "$LINENO" 5
 fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+
+done
 
 fi
-as_val=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-   if test "x$as_val" = x""yes; then
+
+if test x$UDEV_SYNC = xyes; then
+       for ac_header in sys/ipc.h sys/sem.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
   cat >>confdefs.h <<_ACEOF
 #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
 _ACEOF
 
 else
-  { { $as_echo "$as_me:$LINENO: error: bailing out" >&5
-$as_echo "$as_me: error: bailing out" >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error $? "bailing out" "$LINENO" 5
 fi
 
 done
@@ -17991,9 +10436,9 @@ fi
 ################################################################################
 # Extract the first word of "modprobe", so it can be a program name with args.
 set dummy modprobe; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_path_MODPROBE_CMD+set}" = set; then
+if test "${ac_cv_path_MODPROBE_CMD+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   case $MODPROBE_CMD in
@@ -18006,14 +10451,14 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_path_MODPROBE_CMD="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
   ;;
@@ -18021,10 +10466,10 @@ esac
 fi
 MODPROBE_CMD=$ac_cv_path_MODPROBE_CMD
 if test -n "$MODPROBE_CMD"; then
-  { $as_echo "$as_me:$LINENO: result: $MODPROBE_CMD" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MODPROBE_CMD" >&5
 $as_echo "$MODPROBE_CMD" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
 lvm_exec_prefix=$exec_prefix
 test "$lvm_exec_prefix" = NONE && lvm_exec_prefix=$prefix
 test "$lvm_exec_prefix" = NONE && lvm_exec_prefix=$ac_default_prefix
+LVM_PATH="$lvm_exec_prefix/sbin/lvm"
 
 cat >>confdefs.h <<_ACEOF
-#define LVM_PATH "$lvm_exec_prefix/sbin/lvm"
+#define LVM_PATH "$LVM_PATH"
 _ACEOF
 
 
 if  test "$CLVMD" != none; then
         clvmd_prefix=$ac_default_prefix
+        CLVMD_PATH="$clvmd_prefix/sbin/clvmd"
         test "$prefix" != NONE && clvmd_prefix=$prefix
 
 cat >>confdefs.h <<_ACEOF
-#define CLVMD_PATH "$clvmd_prefix/sbin/clvmd"
+#define CLVMD_PATH "$CLVMD_PATH"
 _ACEOF
 
 fi
 if test "$BUILD_DMEVENTD" = yes; then
 
 # Check whether --with-dmeventd-pidfile was given.
-if test "${with_dmeventd_pidfile+set}" = set; then
+if test "${with_dmeventd_pidfile+set}" = set; then :
   withval=$with_dmeventd_pidfile; DMEVENTD_PIDFILE=$withval
 else
-  DMEVENTD_PIDFILE="/var/run/dmeventd.pid"
+  DMEVENTD_PIDFILE="$DEFAULT_PID_DIR/dmeventd.pid"
 fi
 
 
@@ -18078,7 +10525,7 @@ fi
 if test "$BUILD_DMEVENTD" = yes; then
 
 # Check whether --with-dmeventd-path was given.
-if test "${with_dmeventd_path+set}" = set; then
+if test "${with_dmeventd_path+set}" = set; then :
   withval=$with_dmeventd_path; DMEVENTD_PATH=$withval
 else
   DMEVENTD_PATH="$lvm_exec_prefix/sbin/dmeventd"
@@ -18091,25 +10538,10 @@ _ACEOF
 
 fi
 
-
-
-
-# Check whether --with-default-run-dir was given.
-if test "${with_default_run_dir+set}" = set; then
-  withval=$with_default_run_dir;  DEFAULT_RUN_DIR="$withval"
-else
-   DEFAULT_RUN_DIR="/var/run/lvm"
-fi
-
-cat >>confdefs.h <<_ACEOF
-#define DEFAULT_RUN_DIR "$DEFAULT_RUN_DIR"
-_ACEOF
-
-
 ################################################################################
 
 # Check whether --with-default-system-dir was given.
-if test "${with_default_system_dir+set}" = set; then
+if test "${with_default_system_dir+set}" = set; then :
   withval=$with_default_system_dir; DEFAULT_SYS_DIR=$withval
 else
   DEFAULT_SYS_DIR="/etc/lvm"
@@ -18123,7 +10555,7 @@ _ACEOF
 
 
 # Check whether --with-default-archive-subdir was given.
-if test "${with_default_archive_subdir+set}" = set; then
+if test "${with_default_archive_subdir+set}" = set; then :
   withval=$with_default_archive_subdir; DEFAULT_ARCHIVE_SUBDIR=$withval
 else
   DEFAULT_ARCHIVE_SUBDIR=archive
@@ -18137,7 +10569,7 @@ _ACEOF
 
 
 # Check whether --with-default-backup-subdir was given.
-if test "${with_default_backup_subdir+set}" = set; then
+if test "${with_default_backup_subdir+set}" = set; then :
   withval=$with_default_backup_subdir; DEFAULT_BACKUP_SUBDIR=$withval
 else
   DEFAULT_BACKUP_SUBDIR=backup
@@ -18151,7 +10583,7 @@ _ACEOF
 
 
 # Check whether --with-default-cache-subdir was given.
-if test "${with_default_cache_subdir+set}" = set; then
+if test "${with_default_cache_subdir+set}" = set; then :
   withval=$with_default_cache_subdir; DEFAULT_CACHE_SUBDIR=$withval
 else
   DEFAULT_CACHE_SUBDIR=cache
@@ -18165,7 +10597,7 @@ _ACEOF
 
 
 # Check whether --with-default-locking-dir was given.
-if test "${with_default_locking_dir+set}" = set; then
+if test "${with_default_locking_dir+set}" = set; then :
   withval=$with_default_locking_dir; DEFAULT_LOCK_DIR=$withval
 else
   DEFAULT_LOCK_DIR="/var/lock/lvm"
@@ -18180,7 +10612,7 @@ _ACEOF
 ################################################################################
 
 # Check whether --with-default-data-alignment was given.
-if test "${with_default_data_alignment+set}" = set; then
+if test "${with_default_data_alignment+set}" = set; then :
   withval=$with_default_data_alignment; DEFAULT_DATA_ALIGNMENT=$withval
 else
   DEFAULT_DATA_ALIGNMENT=1
@@ -18193,11 +10625,11 @@ _ACEOF
 
 
 ################################################################################
-{ $as_echo "$as_me:$LINENO: checking for kernel interface choice" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for kernel interface choice" >&5
 $as_echo_n "checking for kernel interface choice... " >&6; }
 
 # Check whether --with-interface was given.
-if test "${with_interface+set}" = set; then
+if test "${with_interface+set}" = set; then :
   withval=$with_interface; interface=$withval
 else
   interface=ioctl
 
 if [ "x$interface" != xioctl ];
 then
-  { { $as_echo "$as_me:$LINENO: error: --with-interface=ioctl required. fs no longer supported." >&5
-$as_echo "$as_me: error: --with-interface=ioctl required. fs no longer supported." >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error $? "--with-interface=ioctl required. fs no longer supported." "$LINENO" 5
 fi
-{ $as_echo "$as_me:$LINENO: result: $interface" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $interface" >&5
 $as_echo "$interface" >&6; }
 
 ################################################################################
@@ -18315,6 +10745,27 @@ LVM_LIBAPI=`echo "$VER" | $AWK -F '[()]' '{print $2}'`
 
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 
 
 
@@ -18337,7 +10788,7 @@ LVM_LIBAPI=`echo "$VER" | $AWK -F '[()]' '{print $2}'`
 
 
 ################################################################################
-ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile doc/Makefile doc/example.conf include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile lib/misc/lvm-version.h lib/snapshot/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/lvm2_monitoring_init_red_hat scripts/Makefile test/Makefile test/api/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile"
+ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmetad/Makefile doc/Makefile doc/example.conf include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile lib/misc/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/dm_event_systemd_red_hat.socket scripts/dm_event_systemd_red_hat.service scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_tmpfiles_red_hat.conf scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile"
 
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
@@ -18366,13 +10817,13 @@ _ACEOF
     case $ac_val in #(
     *${as_nl}*)
       case $ac_var in #(
-      *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
       esac
       case $ac_var in #(
       _ | IFS | as_nl) ;; #(
       BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
-      *) $as_unset $ac_var ;;
+      *) { eval $ac_var=; unset $ac_var;} ;;
       esac ;;
     esac
   done
@@ -18380,8 +10831,8 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
   (set) 2>&1 |
     case $as_nl`(ac_space=' '; set) 2>&1` in #(
     *${as_nl}ac_space=\ *)
-      # `set' does not quote correctly, so add quotes (double-quote
-      # substitution turns \\\\ into \\, and sed turns \\ into \).
+      # `set' does not quote correctly, so add quotesdouble-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
       sed -n \
        "s/'/'\\\\''/g;
          s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
@@ -18404,11 +10855,11 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
 if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
   if test -w "$cache_file"; then
     test "x$cache_file" != "x/dev/null" &&
-      { $as_echo "$as_me:$LINENO: updating cache $cache_file" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
 $as_echo "$as_me: updating cache $cache_file" >&6;}
     cat confcache >$cache_file
   else
-    { $as_echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
   fi
 fi
@@ -18422,14 +10873,15 @@ DEFS=-DHAVE_CONFIG_H
 
 ac_libobjs=
 ac_ltlibobjs=
+U=
 for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
   # 1. Remove the extension, and $U if already installed.
   ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
   ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
   # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
   #    will be set to the directory where LIBOBJS objects are built.
-  ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext"
-  ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo'
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
 done
 LIBOBJS=$ac_libobjs
 
@@ -18441,9 +10893,10 @@ LTLIBOBJS=$ac_ltlibobjs
 ac_write_fail=0
 ac_clean_files_save=$ac_clean_files
 ac_clean_files="$ac_clean_files $CONFIG_STATUS"
-{ $as_echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
-cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
 #! $SHELL
 # Generated by $as_me.
 # Run this file to recreate the current configuration.
@@ -18453,17 +10906,18 @@ cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 debug=false
 ac_cs_recheck=false
 ac_cs_silent=false
-SHELL=\${CONFIG_SHELL-$SHELL}
-_ACEOF
 
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-## --------------------- ##
-## M4sh Initialization.  ##
-## --------------------- ##
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
 
 # Be more Bourne compatible
 DUALCASE=1; export DUALCASE # for MKS sh
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
   emulate sh
   NULLCMD=:
   # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
@@ -18471,23 +10925,15 @@ if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
   alias -g '${1+"$@"}'='"$@"'
   setopt NO_GLOB_SUBST
 else
-  case `(set -o) 2>/dev/null` in
-  *posix*) set -o posix ;;
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
 esac
-
 fi
 
 
-
-
-# PATH needs CR
-# Avoid depending upon Character Ranges.
-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
-as_cr_digits='0123456789'
-as_cr_alnum=$as_cr_Letters$as_cr_digits
-
 as_nl='
 '
 export as_nl
@@ -18495,7 +10941,13 @@ export as_nl
 as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
 as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
 as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
-if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
   as_echo='printf %s\n'
   as_echo_n='printf %s'
 else
@@ -18506,7 +10958,7 @@ else
     as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
     as_echo_n_body='eval
       arg=$1;
-      case $arg in
+      case $arg in #(
       *"$as_nl"*)
        expr "X$arg" : "X\\(.*\\)$as_nl";
        arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
@@ -18529,13 +10981,6 @@ if test "${PATH_SEPARATOR+set}" != set; then
   }
 fi
 
-# Support unset when possible.
-if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
-  as_unset=unset
-else
-  as_unset=false
-fi
-
 
 # IFS
 # We need space, tab and new line, in precisely that order.  Quoting is
 IFS=" ""       $as_nl"
 
 # Find who we are.  Look in the path if we contain no directory separator.
-case $0 in
+case $0 in #((
   *[\\/]* ) as_myself=$0 ;;
   *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
-done
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
 IFS=$as_save_IFS
 
      ;;
@@ -18565,12 +11010,16 @@ if test "x$as_myself" = x; then
 fi
 if test ! -f "$as_myself"; then
   $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
-  { (exit 1); exit 1; }
+  exit 1
 fi
 
-# Work around bugs in pre-3.0 UWIN ksh.
-for as_var in ENV MAIL MAILPATH
-do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
 done
 PS1='$ '
 PS2='> '
@@ -18582,7 +11031,89 @@ export LC_ALL
 LANGUAGE=C
 export LANGUAGE
 
-# Required to use basename.
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
 if expr a : '\(a\)' >/dev/null 2>&1 &&
    test "X`expr 00001 : '.*\(...\)'`" = X001; then
   as_expr=expr
@@ -18596,8 +11127,12 @@ else
   as_basename=false
 fi
 
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
 
-# Name of the executable.
 as_me=`$as_basename -- "$0" ||
 $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
         X"$0" : 'X\(//\)$' \| \
@@ -18617,76 +11152,25 @@ $as_echo X/"$0" |
          }
          s/.*/./; q'`
 
-# CDPATH.
-$as_unset CDPATH
-
-
-
-  as_lineno_1=$LINENO
-  as_lineno_2=$LINENO
-  test "x$as_lineno_1" != "x$as_lineno_2" &&
-  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
-
-  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
-  # uniformly replaced by the line number.  The first 'sed' inserts a
-  # line-number line after each line using $LINENO; the second 'sed'
-  # does the real work.  The second script uses 'N' to pair each
-  # line-number line with the line containing $LINENO, and appends
-  # trailing '-' during substitution so that $LINENO is not a special
-  # case at line end.
-  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
-  # scripts with optimization help from Paolo Bonzini.  Blame Lee
-  # E. McMahon (1931-1989) for sed's syntax.  :-)
-  sed -n '
-    p
-    /[$]LINENO/=
-  ' <$as_myself |
-    sed '
-      s/[$]LINENO.*/&-/
-      t lineno
-      b
-      :lineno
-      N
-      :loop
-      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
-      t loop
-      s/-\n.*//
-    ' >$as_me.lineno &&
-  chmod +x "$as_me.lineno" ||
-    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
-   { (exit 1); exit 1; }; }
-
-  # Don't try to exec as it changes $[0], causing all sort of problems
-  # (the dirname of $[0] is not the place where we might find the
-  # original and so on.  Autoconf is especially sensitive to this).
-  . "./$as_me.lineno"
-  # Exit status is that of the last command.
-  exit
-}
-
-
-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
-  as_dirname=dirname
-else
-  as_dirname=false
-fi
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
 
 ECHO_C= ECHO_N= ECHO_T=
-case `echo -n x` in
+case `echo -n x` in #(((((
 -n*)
-  case `echo 'x\c'` in
+  case `echo 'xy\c'` in
   *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
-  *)   ECHO_C='\c';;
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='        ';;
   esac;;
 *)
   ECHO_N='-n';;
 esac
-if expr a : '\(a\)' >/dev/null 2>&1 &&
-   test "X`expr 00001 : '.*\(...\)'`" = X001; then
-  as_expr=expr
-else
-  as_expr=false
-fi
 
 rm -f conf$$ conf$$.exe conf$$.file
 if test -d conf$$.dir; then
 rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
 rmdir conf$$.dir 2>/dev/null
 
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
 if mkdir -p . 2>/dev/null; then
-  as_mkdir_p=:
+  as_mkdir_p='mkdir -p "$as_dir"'
 else
   test -d ./-p && rmdir ./-p
   as_mkdir_p=false
@@ -18735,10 +11267,10 @@ else
       if test -d "$1"; then
        test -d "$1/.";
       else
-       case $1 in
+       case $1 in #(
        -*)set "./$1";;
        esac;
-       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
        ???[sx]*):;;*)false;;esac;fi
     '\'' sh
   '
@@ -18753,13 +11285,19 @@ as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
 
 
 exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
 
-# Save the log message, to keep $[0] and so on meaningful, and to
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
 This file was extended by $as_me, which was
-generated by GNU Autoconf 2.63.  Invocation command line was
+generated by GNU Autoconf 2.66.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
   CONFIG_HEADERS  = $CONFIG_HEADERS
@@ -18790,13 +11328,15 @@ _ACEOF
 
 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 ac_cs_usage="\
-\`$as_me' instantiates files from templates according to the
-current configuration.
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
 
-Usage: $0 [OPTION]... [FILE]...
+Usage: $0 [OPTION]... [TAG]...
 
   -h, --help       print this help, then exit
   -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
   -q, --quiet, --silent
                    do not print progress messages
   -d, --debug      don't remove temporary files
@@ -18812,16 +11352,17 @@ $config_files
 Configuration headers:
 $config_headers
 
-Report bugs to <bug-autoconf@gnu.org>."
+Report bugs to the package provider."
 
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
 config.status
-configured by $0, generated by GNU Autoconf 2.63,
-  with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+configured by $0, generated by GNU Autoconf 2.66,
+  with options \\"\$ac_cs_config\\"
 
-Copyright (C) 2008 Free Software Foundation, Inc.
+Copyright (C) 2010 Free Software Foundation, Inc.
 This config.status script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it."
 
@@ -18857,6 +11398,8 @@ do
     ac_cs_recheck=: ;;
   --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
     $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
   --debug | --debu | --deb | --de | --d | -d )
     debug=: ;;
   --file | --fil | --fi | --f )
     case $ac_optarg in
     *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
     esac
-    CONFIG_FILES="$CONFIG_FILES '$ac_optarg'"
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
     ac_need_defaults=false;;
   --header | --heade | --head | --hea )
     $ac_shift
     case $ac_optarg in
     *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
     esac
-    CONFIG_HEADERS="$CONFIG_HEADERS '$ac_optarg'"
+    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
     ac_need_defaults=false;;
   --he | --h)
     # Conflict between --help and --header
-    { $as_echo "$as_me: error: ambiguous option: $1
-Try \`$0 --help' for more information." >&2
-   { (exit 1); exit 1; }; };;
+    as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
   --help | --hel | -h )
     $as_echo "$ac_cs_usage"; exit ;;
   -q | -quiet | --quiet | --quie | --qui | --qu | --q \
@@ -18885,11 +11427,10 @@ Try \`$0 --help' for more information." >&2
     ac_cs_silent=: ;;
 
   # This is an error.
-  -*) { $as_echo "$as_me: error: unrecognized option: $1
-Try \`$0 --help' for more information." >&2
-   { (exit 1); exit 1; }; } ;;
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
 
-  *) ac_config_targets="$ac_config_targets $1"
+  *) as_fn_append ac_config_targets " $1"
      ac_need_defaults=false ;;
 
   esac
     "daemons/dmeventd/libdevmapper-event.pc") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/libdevmapper-event.pc" ;;
     "daemons/dmeventd/plugins/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/Makefile" ;;
     "daemons/dmeventd/plugins/lvm2/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/lvm2/Makefile" ;;
+    "daemons/dmeventd/plugins/raid/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/raid/Makefile" ;;
     "daemons/dmeventd/plugins/mirror/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/mirror/Makefile" ;;
     "daemons/dmeventd/plugins/snapshot/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/snapshot/Makefile" ;;
+    "daemons/dmeventd/plugins/thin/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/thin/Makefile" ;;
+    "daemons/lvmetad/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/lvmetad/Makefile" ;;
     "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
     "doc/example.conf") CONFIG_FILES="$CONFIG_FILES doc/example.conf" ;;
     "include/.symlinks") CONFIG_FILES="$CONFIG_FILES include/.symlinks" ;;
     "lib/mirror/Makefile") CONFIG_FILES="$CONFIG_FILES lib/mirror/Makefile" ;;
     "lib/replicator/Makefile") CONFIG_FILES="$CONFIG_FILES lib/replicator/Makefile" ;;
     "lib/misc/lvm-version.h") CONFIG_FILES="$CONFIG_FILES lib/misc/lvm-version.h" ;;
+    "lib/raid/Makefile") CONFIG_FILES="$CONFIG_FILES lib/raid/Makefile" ;;
     "lib/snapshot/Makefile") CONFIG_FILES="$CONFIG_FILES lib/snapshot/Makefile" ;;
+    "lib/thin/Makefile") CONFIG_FILES="$CONFIG_FILES lib/thin/Makefile" ;;
+    "libdaemon/Makefile") CONFIG_FILES="$CONFIG_FILES libdaemon/Makefile" ;;
+    "libdaemon/client/Makefile") CONFIG_FILES="$CONFIG_FILES libdaemon/client/Makefile" ;;
+    "libdaemon/server/Makefile") CONFIG_FILES="$CONFIG_FILES libdaemon/server/Makefile" ;;
     "libdm/Makefile") CONFIG_FILES="$CONFIG_FILES libdm/Makefile" ;;
     "libdm/libdevmapper.pc") CONFIG_FILES="$CONFIG_FILES libdm/libdevmapper.pc" ;;
     "liblvm/Makefile") CONFIG_FILES="$CONFIG_FILES liblvm/Makefile" ;;
     "liblvm/liblvm2app.pc") CONFIG_FILES="$CONFIG_FILES liblvm/liblvm2app.pc" ;;
     "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;;
     "po/Makefile") CONFIG_FILES="$CONFIG_FILES po/Makefile" ;;
+    "python/Makefile") CONFIG_FILES="$CONFIG_FILES python/Makefile" ;;
+    "python/setup.py") CONFIG_FILES="$CONFIG_FILES python/setup.py" ;;
+    "scripts/blkdeactivate.sh") CONFIG_FILES="$CONFIG_FILES scripts/blkdeactivate.sh" ;;
+    "scripts/blk_availability_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/blk_availability_init_red_hat" ;;
+    "scripts/blk_availability_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/blk_availability_systemd_red_hat.service" ;;
     "scripts/clvmd_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/clvmd_init_red_hat" ;;
     "scripts/cmirrord_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/cmirrord_init_red_hat" ;;
+    "scripts/lvm2_lvmetad_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_lvmetad_init_red_hat" ;;
+    "scripts/lvm2_lvmetad_systemd_red_hat.socket") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_lvmetad_systemd_red_hat.socket" ;;
+    "scripts/lvm2_lvmetad_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_lvmetad_systemd_red_hat.service" ;;
     "scripts/lvm2_monitoring_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_monitoring_init_red_hat" ;;
+    "scripts/dm_event_systemd_red_hat.socket") CONFIG_FILES="$CONFIG_FILES scripts/dm_event_systemd_red_hat.socket" ;;
+    "scripts/dm_event_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/dm_event_systemd_red_hat.service" ;;
+    "scripts/lvm2_monitoring_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_monitoring_systemd_red_hat.service" ;;
+    "scripts/lvm2_tmpfiles_red_hat.conf") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_tmpfiles_red_hat.conf" ;;
     "scripts/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;;
     "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
     "test/api/Makefile") CONFIG_FILES="$CONFIG_FILES test/api/Makefile" ;;
+    "test/unit/Makefile") CONFIG_FILES="$CONFIG_FILES test/unit/Makefile" ;;
     "tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
     "udev/Makefile") CONFIG_FILES="$CONFIG_FILES udev/Makefile" ;;
     "unit-tests/datastruct/Makefile") CONFIG_FILES="$CONFIG_FILES unit-tests/datastruct/Makefile" ;;
     "unit-tests/regex/Makefile") CONFIG_FILES="$CONFIG_FILES unit-tests/regex/Makefile" ;;
     "unit-tests/mm/Makefile") CONFIG_FILES="$CONFIG_FILES unit-tests/mm/Makefile" ;;
 
-  *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
-$as_echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
-   { (exit 1); exit 1; }; };;
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
   esac
 done
 
@@ -19005,7 +11565,7 @@ $debug ||
   trap 'exit_status=$?
   { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
 ' 0
-  trap '{ (exit 1); exit 1; }' 1 2 13 15
+  trap 'as_fn_exit 1' 1 2 13 15
 }
 # Create a (secure) tmp directory for tmp files.
 
@@ -19016,11 +11576,7 @@ $debug ||
 {
   tmp=./conf$$-$RANDOM
   (umask 077 && mkdir "$tmp")
-} ||
-{
-   $as_echo "$as_me: cannot create a temporary directory in ." >&2
-   { (exit 1); exit 1; }
-}
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
 
 # Set up the scripts for CONFIG_FILES section.
 # No need to generate them if there are no CONFIG_FILES.
@@ -19028,7 +11584,13 @@ $debug ||
 if test -n "$CONFIG_FILES"; then
 
 
-ac_cr='\r'
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
 ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
 if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
   ac_cs_awk_cr='\\r'
@@ -19045,24 +11607,18 @@ _ACEOF
   echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
   echo "_ACEOF"
 } >conf$$subs.sh ||
-  { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
-$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
-   { (exit 1); exit 1; }; }
-ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'`
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
 ac_delim='%!_!# '
 for ac_last_try in false false false false false :; do
   . ./conf$$subs.sh ||
-    { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
-$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
-   { (exit 1); exit 1; }; }
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
 
   ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
   if test $ac_delim_n = $ac_delim_num; then
     break
   elif $ac_last_try; then
-    { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
-$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
-   { (exit 1); exit 1; }; }
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
   else
     ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
   fi
@@ -19084,7 +11640,7 @@ s/'"$ac_delim"'$//
 t delim
 :nl
 h
-s/\(.\{148\}\).*/\1/
+s/\(.\{148\}\)..*/\1/
 t more1
 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
 p
@@ -19098,7 +11654,7 @@ s/.\{148\}//
 t nl
 :delim
 h
-s/\(.\{148\}\).*/\1/
+s/\(.\{148\}\)..*/\1/
 t more2
 s/["\\]/\\&/g; s/^/"/; s/$/"/
 p
@@ -19151,22 +11707,28 @@ if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
 else
   cat
 fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
-  || { { $as_echo "$as_me:$LINENO: error: could not setup config files machinery" >&5
-$as_echo "$as_me: error: could not setup config files machinery" >&2;}
-   { (exit 1); exit 1; }; }
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
 _ACEOF
 
-# VPATH may cause trouble with some makes, so we remove $(srcdir),
-# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
 # trailing colons and then remove the whole line if VPATH becomes empty
 # (actually we leave an empty line to preserve line numbers).
 if test "x$srcdir" = x.; then
-  ac_vpsub='/^[         ]*VPATH[        ]*=/{
-s/:*\$(srcdir):*/:/
-s/:*\${srcdir}:*/:/
-s/:*@srcdir@:*/:/
-s/^\([^=]*=[    ]*\):*/\1/
+  ac_vpsub='/^[         ]*VPATH[        ]*=[    ]*/{
+h
+s///
+s/^/:/
+s/[     ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
 s/:*$//
+x
+s/\(=[  ]*\).*/\1/
+G
+s/\n//
 s/^[^=]*=[      ]*$//
 }'
 fi
@@ -19194,9 +11756,7 @@ for ac_last_try in false false :; do
   if test -z "$ac_t"; then
     break
   elif $ac_last_try; then
-    { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_HEADERS" >&5
-$as_echo "$as_me: error: could not make $CONFIG_HEADERS" >&2;}
-   { (exit 1); exit 1; }; }
+    as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
   else
     ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
   fi
@@ -19281,9 +11841,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 _ACAWK
 _ACEOF
 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-  { { $as_echo "$as_me:$LINENO: error: could not setup config headers machinery" >&5
-$as_echo "$as_me: error: could not setup config headers machinery" >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
 fi # test -n "$CONFIG_HEADERS"
 
 
@@ -19296,9 +11854,7 @@ do
   esac
   case $ac_mode$ac_tag in
   :[FHL]*:*);;
-  :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: invalid tag $ac_tag" >&5
-$as_echo "$as_me: error: invalid tag $ac_tag" >&2;}
-   { (exit 1); exit 1; }; };;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
   :[FH]-) ac_tag=-:-;;
   :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
   esac
@@ -19326,12 +11882,10 @@ $as_echo "$as_me: error: invalid tag $ac_tag" >&2;}
           [\\/$]*) false;;
           *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
           esac ||
-          { { $as_echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5
-$as_echo "$as_me: error: cannot find input file: $ac_f" >&2;}
-   { (exit 1); exit 1; }; };;
+          as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
       esac
       case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
-      ac_file_inputs="$ac_file_inputs '$ac_f'"
+      as_fn_append ac_file_inputs " '$ac_f'"
     done
 
     # Let's still pretend it is `configure' which instantiates (i.e., don't
@@ -19342,7 +11896,7 @@ $as_echo "$as_me: error: cannot find input file: $ac_f" >&2;}
        `' by configure.'
     if test x"$ac_file" != x-; then
       configure_input="$ac_file.  $configure_input"
-      { $as_echo "$as_me:$LINENO: creating $ac_file" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
 $as_echo "$as_me: creating $ac_file" >&6;}
     fi
     # Neutralize special characters interpreted by sed in replacement strings.
@@ -19355,9 +11909,7 @@ $as_echo "$as_me: creating $ac_file" >&6;}
 
     case $ac_tag in
     *:-:* | *:-) cat >"$tmp/stdin" \
-      || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
-$as_echo "$as_me: error: could not create $ac_file" >&2;}
-   { (exit 1); exit 1; }; } ;;
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
     esac
     ;;
   esac
@@ -19385,47 +11937,7 @@ $as_echo X"$ac_file" |
            q
          }
          s/.*/./; q'`
-  { as_dir="$ac_dir"
-  case $as_dir in #(
-  -*) as_dir=./$as_dir;;
-  esac
-  test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
-    as_dirs=
-    while :; do
-      case $as_dir in #(
-      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
-      *) as_qdir=$as_dir;;
-      esac
-      as_dirs="'$as_qdir' $as_dirs"
-      as_dir=`$as_dirname -- "$as_dir" ||
-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-        X"$as_dir" : 'X\(//\)[^/]' \| \
-        X"$as_dir" : 'X\(//\)$' \| \
-        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_dir" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)[^/].*/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-      test -d "$as_dir" && break
-    done
-    test -z "$as_dirs" || eval "mkdir $as_dirs"
-  } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
-$as_echo "$as_me: error: cannot create directory $as_dir" >&2;}
-   { (exit 1); exit 1; }; }; }
+  as_dir="$ac_dir"; as_fn_mkdir_p
   ac_builddir=.
 
 case "$ac_dir" in
@@ -19482,7 +11994,6 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # If the template does not know about datarootdir, expand it.
 # FIXME: This hack should be removed a few years after 2.60.
 ac_datarootdir_hack=; ac_datarootdir_seen=
-
 ac_sed_dataroot='
 /datarootdir/ {
   p
@@ -19492,12 +12003,11 @@ ac_sed_dataroot='
 /@docdir@/p
 /@infodir@/p
 /@localedir@/p
-/@mandir@/p
-'
+/@mandir@/p'
 case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
 *datarootdir*) ac_datarootdir_seen=yes;;
 *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
-  { $as_echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
@@ -19507,7 +12017,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
   s&@infodir@&$infodir&g
   s&@localedir@&$localedir&g
   s&@mandir@&$mandir&g
-    s&\\\${datarootdir}&$datarootdir&g' ;;
+  s&\\\${datarootdir}&$datarootdir&g' ;;
 esac
 _ACEOF
 
@@ -19536,26 +12046,22 @@ s&@MKDIR_P@&$ac_MKDIR_P&;t t
 $ac_datarootdir_hack
 "
 eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
-  || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
-$as_echo "$as_me: error: could not create $ac_file" >&2;}
-   { (exit 1); exit 1; }; }
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
 
 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
   { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
   { ac_out=`sed -n '/^[         ]*datarootdir[  ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
-  { $as_echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined.  Please make sure it is defined." >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined.  Please make sure it is defined." >&2;}
+which seems to be undefined.  Please make sure it is defined" >&2;}
 
   rm -f "$tmp/stdin"
   case $ac_file in
   -) cat "$tmp/out" && rm -f "$tmp/out";;
   *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
   esac \
-  || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
-$as_echo "$as_me: error: could not create $ac_file" >&2;}
-   { (exit 1); exit 1; }; }
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
  ;;
   :H)
   #
@@ -19566,25 +12072,19 @@ $as_echo "$as_me: error: could not create $ac_file" >&2;}
       $as_echo "/* $configure_input  */" \
       && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs"
     } >"$tmp/config.h" \
-      || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
-$as_echo "$as_me: error: could not create $ac_file" >&2;}
-   { (exit 1); exit 1; }; }
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5
     if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then
-      { $as_echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
 $as_echo "$as_me: $ac_file is unchanged" >&6;}
     else
       rm -f "$ac_file"
       mv "$tmp/config.h" "$ac_file" \
-       || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
-$as_echo "$as_me: error: could not create $ac_file" >&2;}
-   { (exit 1); exit 1; }; }
+       || as_fn_error $? "could not create $ac_file" "$LINENO" 5
     fi
   else
     $as_echo "/* $configure_input  */" \
       && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \
-      || { { $as_echo "$as_me:$LINENO: error: could not create -" >&5
-$as_echo "$as_me: error: could not create -" >&2;}
-   { (exit 1); exit 1; }; }
+      || as_fn_error $? "could not create -" "$LINENO" 5
   fi
  ;;
 
@@ -19594,15 +12094,12 @@ $as_echo "$as_me: error: could not create -" >&2;}
 done # for ac_tag
 
 
-{ (exit 0); exit 0; }
+as_fn_exit 0
 _ACEOF
-chmod +x $CONFIG_STATUS
 ac_clean_files=$ac_clean_files_save
 
 test $ac_write_fail = 0 ||
-  { { $as_echo "$as_me:$LINENO: error: write failure creating $CONFIG_STATUS" >&5
-$as_echo "$as_me: error: write failure creating $CONFIG_STATUS" >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
 
 
 # configure is writing to config.log, and then calls config.status.
@@ -19623,15 +12120,15 @@ if test "$no_create" != yes; then
   exec 5>>config.log
   # Use ||, not &&, to avoid exiting from the if with $? = 1, which
   # would make configure fail if this is the last instruction.
-  $ac_cs_success || { (exit 1); exit 1; }
+  $ac_cs_success || as_fn_exit 1
 fi
 if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
-  { $as_echo "$as_me:$LINENO: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
 fi
 
 
 if test x$ODIRECT != xyes; then
-  { $as_echo "$as_me:$LINENO: WARNING: Warning: O_DIRECT disabled: low-memory pvmove may lock up" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Warning: O_DIRECT disabled: low-memory pvmove may lock up" >&5
 $as_echo "$as_me: WARNING: Warning: O_DIRECT disabled: low-memory pvmove may lock up" >&2;}
 fi
index 6cb5e8dbeedd0f6980b1270553ca62ea4b37bcfd..75e0d843c3cb5edbe933dfe98d35f66494598f0b 100644 (file)
@@ -1,6 +1,6 @@
 ###############################################################################
 ## Copyright (C) 2000-2004 Sistina Software, Inc. All rights reserved.
-## Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
+## Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
 ##
 ## This copyrighted material is made available to anyone wishing to use,
 ## modify, copy, or redistribute it subject to the terms and conditions
@@ -31,22 +31,26 @@ case "$host_os" in
                CFLAGS="$CFLAGS"
                COPTIMISE_FLAG="-O2"
                CLDFLAGS="$CLDFLAGS -Wl,--version-script,.export.sym"
+               ELDFLAGS="-Wl,--export-dynamic"
+               # FIXME Generate list and use --dynamic-list=.dlopen.sym
                CLDWHOLEARCHIVE="-Wl,-whole-archive"
                CLDNOWHOLEARCHIVE="-Wl,-no-whole-archive"
                LDDEPS="$LDDEPS .export.sym"
-               LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
                LIB_SUFFIX=so
                DEVMAPPER=yes
+               LVMETAD=no
                ODIRECT=yes
                DM_IOCTLS=yes
                SELINUX=yes
                CLUSTER=internal
                FSADM=yes
+               BLKDEACTIVATE=yes
                ;;
        darwin*)
                CFLAGS="$CFLAGS -no-cpp-precomp -fno-common"
                COPTIMISE_FLAG="-O2"
                CLDFLAGS="$CLDFLAGS"
+               ELDFLAGS=
                CLDWHOLEARCHIVE="-all_load"
                CLDNOWHOLEARCHIVE=
                LIB_SUFFIX=dylib
@@ -56,6 +60,7 @@ case "$host_os" in
                SELINUX=no
                CLUSTER=none
                FSADM=no
+               BLKDEACTIVATE=no
                ;;
 esac
 
@@ -213,6 +218,33 @@ AC_ARG_WITH(device-mode,
            DM_DEVICE_MODE=$withval, DM_DEVICE_MODE=0600)
 AC_MSG_RESULT($DM_DEVICE_MODE)
 
+AC_MSG_CHECKING(when to create device nodes)
+AC_ARG_WITH(device-nodes-on,
+           AC_HELP_STRING([--with-device-nodes-on=ON],
+                          [create nodes on resume or create [[ON=resume]]]),
+           ADD_NODE=$withval, ADD_NODE=resume)
+case "$ADD_NODE" in
+ resume) add_on=DM_ADD_NODE_ON_RESUME;;
+ create) add_on=DM_ADD_NODE_ON_CREATE;;
+ *) AC_MSG_ERROR([--with-device-nodes-on parameter invalid]);;
+esac
+AC_MSG_RESULT(on $ADD_NODE)
+AC_DEFINE_UNQUOTED([DEFAULT_DM_ADD_NODE], $add_on, [Define default node creation behavior with dmsetup create])
+
+AC_MSG_CHECKING(default name mangling)
+AC_ARG_WITH(default-name-mangling,
+           AC_HELP_STRING([--with-default-name-mangling=MANGLING],
+                          [default name mangling: auto/none/hex [[MANGLING=auto]]]),
+           MANGLING=$withval, MANGLING=auto)
+case "$MANGLING" in
+ auto) mangling=DM_STRING_MANGLING_AUTO;;
+ disabled) mangling=DM_STRING_MANGLING_NONE;;
+ hex) mangling=DM_STRING_MANGLING_HEX;;
+ *) AC_MSG_ERROR([--with-default-name-mangling parameter invalid]);;
+esac
+AC_MSG_RESULT($MANGLING)
+AC_DEFINE_UNQUOTED([DEFAULT_DM_NAME_MANGLING], $mangling, [Define default name mangling behaviour])
+
 ################################################################################
 dnl -- LVM1 tool fallback option
 AC_MSG_CHECKING(whether to enable lvm1 fallback)
@@ -327,6 +359,26 @@ if test x$MIRRORS = xinternal; then
        AC_DEFINE([MIRRORED_INTERNAL], 1, [Define to 1 to include built-in support for mirrors.])
 fi
 
+################################################################################
+dnl -- raid inclusion type
+AC_MSG_CHECKING(whether to include raid)
+AC_ARG_WITH(raid,
+           AC_HELP_STRING([--with-raid=TYPE],
+                          [mirror support: internal/shared/none
+                           [[TYPE=internal]]]),
+           RAID=$withval, RAID=internal)
+AC_MSG_RESULT($RAID)
+
+if [[ "x$RAID" != xnone -a "x$RAID" != xinternal -a "x$RAID" != xshared ]];
+ then  AC_MSG_ERROR(
+--with-raid parameter invalid
+)
+fi;
+
+if test x$RAID = xinternal; then
+       AC_DEFINE([RAID_INTERNAL], 1, [Define to 1 to include built-in support for raid.])
+fi
+
 ################################################################################
 dnl -- asynchronous volume replicator inclusion type
 AC_MSG_CHECKING(whether to include replicators)
@@ -344,6 +396,41 @@ case "$REPLICATORS" in
   *) AC_MSG_ERROR([--with-replicators parameter invalid ($REPLICATORS)]) ;;
 esac
 
+################################################################################
+dnl -- thin provisioning
+AC_MSG_CHECKING(whether to include thin provisioning)
+AC_ARG_WITH(thin,
+           AC_HELP_STRING([--with-thin=TYPE],
+                          [thin provisioning support: internal/shared/none
+                           [[TYPE=none]]]),
+           THIN=$withval, THIN=none)
+AC_MSG_RESULT($THIN)
+
+case "$THIN" in
+  none|shared) ;;
+  internal) AC_DEFINE([THIN_INTERNAL], 1,
+               [Define to 1 to include built-in support for thin provisioning.]) ;;
+  *) AC_MSG_ERROR([--with-thin parameter invalid ($THIN)]) ;;
+esac
+
+case "$THIN" in
+  internal|shared)
+       AC_ARG_WITH(thin-check,
+               AC_HELP_STRING([--with-thin-check=PATH],
+                              [thin_check tool: [[autodetect]]]),
+                              THIN_CHECK_CMD=$withval, THIN_CHECK_CMD="autodetect")
+       # Empty means a config way to ignore thin checking
+       if test "$THIN_CHECK_CMD" = "autodetect"; then
+               AC_PATH_PROG(THIN_CHECK_CMD, thin_check)
+               test -z "$THIN_CHECK_CMD" && AC_MSG_ERROR(thin_check not found in path $PATH)
+       fi
+       ;;
+esac
+
+AC_DEFINE_UNQUOTED([THIN_CHECK_CMD], ["$THIN_CHECK_CMD"],
+                  [The path to 'thin_check', if available.])
+
+
 ################################################################################
 dnl -- Disable readline
 AC_MSG_CHECKING(whether to enable readline)
@@ -368,6 +455,10 @@ AC_ARG_ENABLE(ocf,
                             [enable Open Cluster Framework (OCF) compliant resource agents]),
              OCF=$enableval, OCF=no)
 AC_MSG_RESULT($OCF)
+AC_ARG_WITH(ocfdir,
+           AC_HELP_STRING([--with-ocfdir=DIR],
+                          [install OCF files in DIR [[PREFIX/lib/ocf/resource.d/lvm2]]]),
+           OCFDIR=$withval, OCFDIR='${prefix}/lib/ocf/resource.d/lvm2')
 
 ################################################################################
 dnl -- Init pkg-config with dummy invokation:
@@ -380,13 +471,38 @@ pkg_config_init() {
        PKGCONFIG_INIT=1
 }
 
+################################################################################
+dnl -- Set up pidfile and run directory
+AH_TEMPLATE(DEFAULT_PID_DIR)
+AC_ARG_WITH(default-pid-dir,
+           AC_HELP_STRING([--with-default-pid-dir=PID_DIR],
+                          [Default directory to keep PID files in. [[/var/run]]]),
+           DEFAULT_PID_DIR="$withval", DEFAULT_PID_DIR="/var/run")
+AC_DEFINE_UNQUOTED(DEFAULT_PID_DIR, ["$DEFAULT_PID_DIR"],
+                  [Default directory to keep PID files in.])
+
+AH_TEMPLATE(DEFAULT_DM_RUN_DIR, [Name of default DM run directory.])
+AC_ARG_WITH(default-dm-run-dir,
+           AC_HELP_STRING([--with-default-dm-run-dir=DM_RUN_DIR],
+                          [ Default DM run directory. [[/var/run]]]),
+           DEFAULT_DM_RUN_DIR="$withval", DEFAULT_DM_RUN_DIR="/var/run")
+AC_DEFINE_UNQUOTED(DEFAULT_DM_RUN_DIR, ["$DEFAULT_DM_RUN_DIR"],
+                  [Default DM run directory.])
+
+AH_TEMPLATE(DEFAULT_RUN_DIR, [Name of default LVM run directory.])
+AC_ARG_WITH(default-run-dir,
+           AC_HELP_STRING([--with-default-run-dir=RUN_DIR],
+                          [Default LVM run directory. [[/var/run/lvm]]]),
+           DEFAULT_RUN_DIR="$withval", DEFAULT_RUN_DIR="/var/run/lvm")
+AC_DEFINE_UNQUOTED(DEFAULT_RUN_DIR, ["$DEFAULT_RUN_DIR"],
+                  [Default LVM run directory.])
+
 ################################################################################
 dnl -- Build cluster LVM daemon
 AC_MSG_CHECKING(whether to build cluster LVM daemon)
 AC_ARG_WITH(clvmd,
   [  --with-clvmd=TYPE       build cluster LVM Daemon
                           The following cluster manager combinations are valid:
-                           * cman,gulm             (RHEL4 or equivalent)
                            * cman                  (RHEL5 or equivalent)
                            * cman,corosync,openais (or selection of them)
                            * singlenode            (localhost only)
@@ -412,14 +528,12 @@ fi
 dnl -- Express clvmd init script Required-Start / Required-Stop
 CLVMD_CMANAGERS=""
 dnl -- On RHEL4/RHEL5, qdiskd is started from a separate init script.
-dnl -- Enable if we are build for either cman or gulm.
+dnl -- Enable if we are build for cman.
 CLVMD_NEEDS_QDISKD=no
 
 dnl -- define build types
 if [[ `expr x"$CLVMD" : '.*gulm.*'` != 0 ]]; then
-       BUILDGULM=yes
-       CLVMD_CMANAGERS="$CLVMD_CMANAGERS lock_gulmd"
-       CLVMD_NEEDS_QDISKD=yes
+       AC_MSG_ERROR([Since version 2.02.87 GULM locking is no longer supported.]);
 fi
 if [[ `expr x"$CLVMD" : '.*cman.*'` != 0 ]]; then
        BUILDCMAN=yes
@@ -438,14 +552,6 @@ if test x$CLVMD_NEEDS_QDISKD != xno; then
        CLVMD_CMANAGERS="$CLVMD_CMANAGERS qdiskd"
 fi
 
-dnl -- sanity check around user selection
-if test x$BUILDGULM = xyes; then
-       if test x$BUILDCOROSYNC = xyes || \
-          test x$BUILDOPENAIS = xyes; then
-               AC_MSG_ERROR([requested clvmd configuration is not valid])
-       fi
-fi
-
 dnl -- define a soft bailout if we are autodetecting
 soft_bailout() {
        NOTFOUND=1
@@ -457,10 +563,9 @@ hard_bailout() {
 
 dnl -- if clvmd=all then set soft_bailout (we don't want to error)
 dnl -- and set all builds to yes. We need to do this here
-dnl -- to skip the gulm + openais|corosync sanity check above.
+dnl -- to skip the openais|corosync sanity check above.
 if test x$CLVMD = xall; then
        bailout=soft_bailout
-       BUILDGULM=yes
        BUILDCMAN=yes
        BUILDCOROSYNC=yes
        BUILDOPENAIS=yes
@@ -482,28 +587,6 @@ check_lib_no_libs() {
        LIBS=$ac_check_lib_save_LIBS
 }
 
-dnl -- Look for gulm libraries if required.
-if test x$BUILDGULM = xyes; then
-       PKG_CHECK_MODULES(CCS, libccs, [HAVE_CCS=yes],
-               [NOTFOUND=0
-               AC_CHECK_HEADERS(ccs.h,,$bailout)
-               check_lib_no_libs ccs ccs_connect
-               if test $NOTFOUND = 0; then
-                       AC_MSG_RESULT([no pkg for libccs, using -lccs])
-                       CCS_LIBS="-lccs"
-                       HAVE_CCS=yes
-               fi])
-       PKG_CHECK_MODULES(GULM, libgulm, [HAVE_GULM=yes],
-               [NOTFOUND=0
-               AC_CHECK_HEADERS(libgulm.h,,$bailout)
-               check_lib_no_libs gulm lg_core_login
-               if test $NOTFOUND = 0; then
-                       AC_MSG_RESULT([no pkg for libgulm, using -lgulm])
-                       GULM_LIBS="-lgulm"
-                       HAVE_GULM=yes
-               fi])
-fi
-
 dnl -- Look for cman libraries if required.
 if test x$BUILDCMAN = xyes; then
        PKG_CHECK_MODULES(CMAN, libcman, [HAVE_CMAN=yes],
@@ -526,6 +609,7 @@ if test x$BUILDCOROSYNC = xyes || \
    test x$BUILDOPENAIS = xyes; then
        PKG_CHECK_MODULES(COROSYNC, corosync, [HAVE_COROSYNC=yes], $bailout)
        CHECKCONFDB=yes
+       CHECKCMAP=yes
 fi
 
 dnl -- Look for corosync libraries if required.
@@ -544,7 +628,7 @@ fi
 dnl -- Below are checks for libraries common to more than one build.
 
 dnl -- Check confdb library.
-dnl -- mandatory for corosync build.
+dnl -- mandatory for corosync < 2.0 build.
 dnl -- optional for openais/cman build.
 
 if test x$CHECKCONFDB = xyes; then
@@ -563,11 +647,34 @@ if test x$CHECKCONFDB = xyes; then
                CONFDB_LIBS="-lconfdb"
                HAVE_CONFDB=yes
        fi
+fi
+
+dnl -- Check cmap library
+dnl -- mandatory for corosync >= 2.0 build.
+
+if test x$CHECKCMAP = xyes; then
+       PKG_CHECK_MODULES(CMAP, libcmap,
+                         [HAVE_CMAP=yes],
+                         [HAVE_CMAP=no])
+
+       AC_CHECK_HEADERS(corosync/cmap.h,
+               [HAVE_CMAP_H=yes],
+               [HAVE_CMAP_H=no])
+
+       if test x$HAVE_CMAP != xyes && \ 
+          test x$HAVE_CMAP_H = xyes; then
+               check_lib_no_libs cmap cmap_initialize
+               AC_MSG_RESULT([no pkg for cmap, using -lcmap])
+               CMAP_LIBS="-lcmap"
+               HAVE_CMAP=yes
+       fi
+fi
 
-       if test x$BUILDCOROSYNC = xyes && \
-          test x$HAVE_CONFDB != xyes &&
+if test x$BUILDCOROSYNC = xyes; then
+       if test x$HAVE_CMAP != xyes && \
+          test x$HAVE_CONFDB != xyes && \
           test x$CLVMD != xall; then
-               AC_MSG_ERROR([bailing out... confdb library is required])
+               AC_MSG_ERROR([bailing out... cmap (corosync >= 2.0) or confdb (corosync < 2.0) library is required])
        fi
 fi
 
@@ -596,13 +703,6 @@ if test x$CLVMD = xall; then
        CLVMD=none
        CLVMD_CMANAGERS=""
        CLVMD_NEEDS_QDISKD=no
-       if test x$HAVE_CCS = xyes && \
-          test x$HAVE_GULM = xyes; then
-               AC_MSG_RESULT([Enabling clvmd gulm cluster manager])
-               CLVMD="$CLVMD,gulm"
-               CLVMD_CMANAGERS="$CLVMD_CMANAGERS lock_gulmd"
-               CLVMD_NEEDS_QDISKD=yes
-       fi
        if test x$HAVE_CMAN = xyes && \
           test x$HAVE_DLM = xyes; then
                AC_MSG_RESULT([Enabling clvmd cman cluster manager])
@@ -613,11 +713,12 @@ if test x$CLVMD = xall; then
        if test x$HAVE_COROSYNC = xyes && \
           test x$HAVE_QUORUM = xyes && \
           test x$HAVE_CPG = xyes && \
-          test x$HAVE_DLM = xyes && \
-          test x$HAVE_CONFDB = xyes; then
+          test x$HAVE_DLM = xyes; then
+          if test x$HAVE_CONFDB = xyes || test x$HAVE_CMAP = xyes; then
                AC_MSG_RESULT([Enabling clvmd corosync cluster manager])
                CLVMD="$CLVMD,corosync"
                CLVMD_CMANAGERS="$CLVMD_CMANAGERS corosync"
+          fi
        fi
        if test x$HAVE_COROSYNC = xyes && \
           test x$HAVE_CPG = xyes && \
@@ -634,14 +735,23 @@ if test x$CLVMD = xall; then
        fi
 fi
 
+dnl -- Fixup CLVMD_CMANAGERS with new corosync
+dnl -- clvmd built with corosync >= 2.0 needs dlm (either init or systemd service)
+dnl -- to be started.
+if [[ `expr x"$CLVMD" : '.*corosync.*'` != 0 ]]; then
+   if test x$HAVE_CMAP = xyes; then
+       CLVMD_CMANAGERS="$CLVMD_CMANAGERS dlm"
+   fi
+fi
+
 ################################################################################
 dnl -- clvmd pidfile
 if test "x$CLVMD" != xnone; then
        AC_ARG_WITH(clvmd-pidfile,
                    AC_HELP_STRING([--with-clvmd-pidfile=PATH],
-                                  [clvmd pidfile [[/var/run/clvmd.pid]]]),
+                                  [clvmd pidfile [[PID_DIR/clvmd.pid]]]),
                    CLVMD_PIDFILE=$withval,
-                   CLVMD_PIDFILE="/var/run/clvmd.pid")
+                   CLVMD_PIDFILE="$DEFAULT_PID_DIR/clvmd.pid")
        AC_DEFINE_UNQUOTED(CLVMD_PIDFILE, ["$CLVMD_PIDFILE"],
                           [Path to clvmd pidfile.])
 fi
@@ -662,9 +772,9 @@ dnl -- cmirrord pidfile
 if test "x$BUILD_CMIRRORD" = xyes; then
        AC_ARG_WITH(cmirrord-pidfile,
                    AC_HELP_STRING([--with-cmirrord-pidfile=PATH],
-                                  [cmirrord pidfile [[/var/run/cmirrord.pid]]]),
+                                  [cmirrord pidfile [[PID_DIR/cmirrord.pid]]]),
                    CMIRRORD_PIDFILE=$withval,
-                   CMIRRORD_PIDFILE="/var/run/cmirrord.pid")
+                   CMIRRORD_PIDFILE="$DEFAULT_PID_DIR/cmirrord.pid")
        AC_DEFINE_UNQUOTED(CMIRRORD_PIDFILE, ["$CMIRRORD_PIDFILE"],
                           [Path to cmirrord pidfile.])
 fi
@@ -676,7 +786,12 @@ if [[ "x$BUILD_CMIRRORD" = xyes ]]; then
        if  test x$PKGCONFIG_INIT != x1; then
                pkg_config_init
        fi
-       PKG_CHECK_MODULES(SACKPT, libSaCkpt)
+
+       AC_DEFINE([CMIRROR_HAS_CHECKPOINT], 1, [Define to 1 to include libSaCkpt.])
+       PKG_CHECK_MODULES(SACKPT, libSaCkpt, [HAVE_SACKPT=yes],
+               [AC_MSG_RESULT([no libSaCkpt, compiling without it])
+               AC_DEFINE([CMIRROR_HAS_CHECKPOINT], 0, [Define to 0 to exclude libSaCkpt.])])
+
        if test x$HAVE_CPG != xyes; then
                PKG_CHECK_MODULES(CPG, libcpg)
        fi
@@ -743,11 +858,10 @@ AC_ARG_ENABLE(testing,
 AC_MSG_RESULT($TESTING)
 
 if test "$TESTING" = yes; then
-   AC_PATH_PROG(RUBY19, ruby1.9)
-   AC_PATH_PROG(VALGRIND, valgrind)
-   if test -z "$RUBY19" -o -z "$VALGRIND"; then
-       AC_MSG_ERROR([ruby1.9 and valgrind are required for testing])
-   fi
+       if  test x$PKGCONFIG_INIT != x1; then
+               pkg_config_init
+       fi
+       PKG_CHECK_MODULES(CUNIT, cunit >= 2.0)
 fi
 
 ################################################################################
@@ -759,8 +873,10 @@ AC_ARG_ENABLE(valgrind_pool,
 AC_MSG_RESULT($VALGRIND_POOL)
 
 if test "$VALGRIND_POOL" = yes; then
-    AC_CHECK_HEADERS([valgrind/memcheck.h], , [AC_MSG_ERROR(bailing out)])
+    PKG_CHECK_MODULES(VALGRIND, valgrind, [], [AC_MSG_ERROR(bailing out)])
     AC_DEFINE([VALGRIND_POOL], 1, [Enable a valgrind aware build of pool])
+    AC_SUBST(VALGRIND_POOL)
+    AC_SUBST(VALGRIND_CFLAGS)
 fi
 
 ################################################################################
@@ -776,6 +892,29 @@ if test x$DEVMAPPER = xyes; then
        AC_DEFINE([DEVMAPPER_SUPPORT], 1, [Define to 1 to enable LVM2 device-mapper interaction.])
 fi
 
+################################################################################
+dnl -- Build lvmetad
+AC_MSG_CHECKING(whether to build LVMetaD)
+AC_ARG_ENABLE(lvmetad,
+             AC_HELP_STRING([--enable-lvmetad],
+                            [enable the LVM Metadata Daemon]),
+             LVMETAD=$enableval)
+AC_MSG_RESULT($LVMETAD)
+
+BUILD_LVMETAD=$LVMETAD
+
+if test x$BUILD_LVMETAD = xyes; then
+       AC_DEFINE([LVMETAD_SUPPORT], 1, [Define to 1 to include code that uses lvmetad.])
+
+       AC_ARG_WITH(lvmetad-pidfile,
+                   AC_HELP_STRING([--with-lvmetad-pidfile=PATH],
+                                  [lvmetad pidfile [[PID_DIR/lvmetad.pid]]]),
+                   LVMETAD_PIDFILE=$withval,
+                   LVMETAD_PIDFILE="$DEFAULT_PID_DIR/lvmetad.pid")
+       AC_DEFINE_UNQUOTED(LVMETAD_PIDFILE, ["$LVMETAD_PIDFILE"],
+                          [Path to lvmetad pidfile.])
+fi
+
 ################################################################################
 dnl -- Enable udev synchronisation
 AC_MSG_CHECKING(whether to enable synchronisation with udev processing)
@@ -786,9 +925,11 @@ AC_ARG_ENABLE(udev_sync,
 AC_MSG_RESULT($UDEV_SYNC)
 
 if test x$UDEV_SYNC = xyes; then
-       AC_CHECK_LIB(udev, udev_queue_get_udev_is_active,
-                    [UDEV_PC="libudev"; UDEV_LIBS="-ludev"],
-                    [AC_MSG_ERROR([bailing out... libudev library is required])])
+       dnl -- init pkgconfig if required
+       if  test x$PKGCONFIG_INIT != x1; then
+               pkg_config_init
+       fi
+       PKG_CHECK_MODULES(UDEV, libudev >= 143, [UDEV_PC="libudev"])
        AC_DEFINE([UDEV_SYNC_SUPPORT], 1, [Define to 1 to enable synchronisation with udev processing.])
 fi
 
@@ -800,6 +941,23 @@ AC_ARG_ENABLE(udev_rules,
              UDEV_RULES=$enableval, UDEV_RULES=$UDEV_SYNC)
 AC_MSG_RESULT($UDEV_RULES)
 
+AC_MSG_CHECKING(whether to enable executable path detection in udev rules)
+AC_ARG_ENABLE(udev_rule_exec_detection,
+             AC_HELP_STRING([--enable-udev-rule-exec-detection],
+                            [enable executable path detection in udev rules]),
+             UDEV_RULE_EXEC_DETECTION=$enableval, UDEV_RULE_EXEC_DETECTION=no)
+AC_MSG_RESULT($UDEV_RULE_EXEC_DETECTION)
+
+dnl -- Check support for built-in blkid against target udev version
+AC_MSG_CHECKING(whether udev supports built-in blkid)
+test x$PKGCONFIG_INIT != x1 && pkg_config_init
+if $($PKG_CONFIG --atleast-version=176 libudev); then
+       UDEV_HAS_BUILTIN_BLKID=yes
+else
+       UDEV_HAS_BUILTIN_BLKID=no
+fi
+AC_MSG_RESULT($UDEV_HAS_BUILTIN_BLKID)
+
 ################################################################################
 dnl -- Compatibility mode
 AC_ARG_ENABLE(compat,
@@ -807,6 +965,14 @@ AC_ARG_ENABLE(compat,
                             [enable support for old device-mapper versions]),
              DM_COMPAT=$enableval, DM_COMPAT=no)
 
+if test x$DM_COMPAT = xyes; then
+       AC_MSG_ERROR(
+                 [--enable-compat is not currently supported.
+Since device-mapper version 1.02.66, only one version (4) of the device-mapper 
+ioctl protocol is supported.]
+       )
+fi
+
 ################################################################################
 dnl -- Compatible units suffix mode
 AC_ARG_ENABLE(units-compat,
@@ -862,6 +1028,40 @@ test x$CMDLIB = xyes \
   && LVM2CMD_LIB=-llvm2cmd \
   || LVM2CMD_LIB=
 
+################################################################################
+dnl -- Enable Python liblvm2app bindings
+AC_MSG_CHECKING(whether to build Python wrapper for liblvm2app.so)
+AC_ARG_ENABLE(python_bindings,
+             AC_HELP_STRING([--enable-python_bindings], [build Python applib bindings]),
+             PYTHON_BINDINGS=$enableval, PYTHON_BINDINGS=no)
+AC_MSG_RESULT($PYTHON_BINDINGS)
+
+if test x$PYTHON_BINDINGS = xyes; then
+       if test x$APPLIB != xyes; then
+               AC_MSG_ERROR(
+                       --enable-python_bindings requires --enable-applib
+               )
+       fi
+
+       AC_PATH_PROG(PYTHON, python, notfound)
+       if test x$PYTHON == xnotfound; then
+               AC_MSG_ERROR(
+[python is required for --enable-python_bindings but cannot be found]
+               )
+       fi
+
+       AC_PATH_PROG(PYTHON_CONFIG, python-config, notfound)
+       if test x$PYTHON_CONFIG == xnotfound; then
+               AC_MSG_ERROR(
+[python headers are required for --enable-python_bindings but cannot be found]
+               )
+       fi
+
+       PYTHON_INCDIRS=`$PYTHON_CONFIG --includes`
+       PYTHON_LIBDIRS=`$PYTHON_CONFIG --libs`
+
+fi
+
 ################################################################################
 dnl -- Enable pkg-config
 AC_ARG_ENABLE(pkgconfig,
@@ -882,6 +1082,13 @@ AC_ARG_ENABLE(fsadm, AC_HELP_STRING([--disable-fsadm], [disable fsadm]),
              FSADM=$enableval)
 AC_MSG_RESULT($FSADM)
 
+################################################################################
+dnl -- Enable blkdeactivate
+AC_MSG_CHECKING(whether to install blkdeactivate)
+AC_ARG_ENABLE(blkdeactivate, AC_HELP_STRING([--disable-blkdeactivate], [disable blkdeactivate]),
+             BLKDEACTIVATE=$enableval)
+AC_MSG_RESULT($BLKDEACTIVATE)
+
 ################################################################################
 dnl -- enable dmeventd handling
 AC_MSG_CHECKING(whether to use dmeventd)
@@ -942,6 +1149,7 @@ AC_CHECK_LIB(dl, dlopen, [
 dnl -- Check for shared/static conflicts
 if [[ \( "x$LVM1" = xshared -o "x$POOL" = xshared -o "x$CLUSTER" = xshared \
       -o "x$SNAPSHOTS" = xshared -o "x$MIRRORS" = xshared \
+      -o "x$RAID" = xshared \
       \) -a "x$STATIC_LINK" = xyes ]];
  then  AC_MSG_ERROR(
 Features cannot be 'shared' when building statically
@@ -1100,6 +1308,34 @@ AC_ARG_WITH(udevdir,
            udevdir=$withval, udevdir='${udev_prefix}/lib/udev/rules.d')
 
 ################################################################################
+dnl -- Get the systemd system unit dir value from pkg_config automatically if value not given explicitly.
+dnl -- This follows the recommendation for systemd integration best practices mentioned in daemon(7) manpage.
+AC_ARG_WITH(systemdsystemunitdir,
+           AC_HELP_STRING([--with-systemdsystemunitdir=DIR],
+                          [systemd service files in DIR]),
+           systemdsystemunitdir=$withval,
+           dnl -- init pkgconfig if required
+           test x$PKGCONFIG_INIT != x1 && pkg_config_init
+           pkg_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd))
+
+if test -n "$pkg_systemdsystemunitdir"; then
+           systemdsystemunitdir=$pkg_systemdsystemunitdir;
+fi
+
+if test -z "$systemdsystemunitdir"; then
+           systemdsystemunitdir='${exec_prefix}/lib/systemd/system';
+fi
+
+systemdutildir=$($PKG_CONFIG --variable=systemdutildir systemd)
+if test -z "$systemdutildir"; then
+           systemdutildir='${exec_prefix}/lib/systemd';
+fi
+################################################################################
+AC_ARG_WITH(tmpfilesdir,
+           AC_HELP_STRING([--with-tmpfilesdir=DIR],
+                          [install configuration files for management of volatile files and directories in DIR [[PREFIX/lib/tmpfiles.d]]]),
+                          tmpfilesdir=$withval, tmpfilesdir='${prefix}/lib/tmpfiles.d')
+################################################################################
 dnl -- Ensure additional headers required
 if test x$READLINE = xyes; then
        AC_CHECK_HEADERS(readline/readline.h readline/history.h,,AC_MSG_ERROR(bailing out))
@@ -1144,13 +1380,14 @@ fi
 lvm_exec_prefix=$exec_prefix
 test "$lvm_exec_prefix" = NONE && lvm_exec_prefix=$prefix
 test "$lvm_exec_prefix" = NONE && lvm_exec_prefix=$ac_default_prefix
-AC_DEFINE_UNQUOTED(LVM_PATH, ["$lvm_exec_prefix/sbin/lvm"], [Path to lvm binary.])
+LVM_PATH="$lvm_exec_prefix/sbin/lvm"
+AC_DEFINE_UNQUOTED(LVM_PATH, ["$LVM_PATH"], [Path to lvm binary.])
 
 if  test "$CLVMD" != none; then
         clvmd_prefix=$ac_default_prefix
+        CLVMD_PATH="$clvmd_prefix/sbin/clvmd"
         test "$prefix" != NONE && clvmd_prefix=$prefix
-       AC_DEFINE_UNQUOTED(CLVMD_PATH, ["$clvmd_prefix/sbin/clvmd"],
-                          [Path to clvmd binary.])
+       AC_DEFINE_UNQUOTED(CLVMD_PATH, ["$CLVMD_PATH"], [Path to clvmd binary.])
 fi
 
 ################################################################################
@@ -1158,9 +1395,9 @@ dnl -- dmeventd pidfile and executable path
 if test "$BUILD_DMEVENTD" = yes; then
        AC_ARG_WITH(dmeventd-pidfile,
                    AC_HELP_STRING([--with-dmeventd-pidfile=PATH],
-                                  [dmeventd pidfile [[/var/run/dmeventd.pid]]]),
+                                  [dmeventd pidfile [[PID_DIR/dmeventd.pid]]]),
                    DMEVENTD_PIDFILE=$withval,
-                   DMEVENTD_PIDFILE="/var/run/dmeventd.pid")
+                   DMEVENTD_PIDFILE="$DEFAULT_PID_DIR/dmeventd.pid")
        AC_DEFINE_UNQUOTED(DMEVENTD_PIDFILE, ["$DMEVENTD_PIDFILE"],
                           [Path to dmeventd pidfile.])
 fi
@@ -1175,13 +1412,6 @@ if test "$BUILD_DMEVENTD" = yes; then
                           [Path to dmeventd binary.])
 fi
 
-AH_TEMPLATE(DEFAULT_RUN_DIR, [Name of default run directory.])
-AC_ARG_WITH(default-run-dir,
-           [  --with-default-run-dir=DIR       Default run directory [[/var/run/lvm]] ],
-           [ DEFAULT_RUN_DIR="$withval" ],
-           [ DEFAULT_RUN_DIR="/var/run/lvm" ])
-AC_DEFINE_UNQUOTED(DEFAULT_RUN_DIR,["$DEFAULT_RUN_DIR"] )
-
 ################################################################################
 dnl -- various defaults
 AC_ARG_WITH(default-system-dir,
@@ -1264,8 +1494,7 @@ AC_SUBST(APPLIB)
 AC_SUBST(AWK)
 AC_SUBST(BUILD_CMIRRORD)
 AC_SUBST(BUILD_DMEVENTD)
-AC_SUBST(CCS_CFLAGS)
-AC_SUBST(CCS_LIBS)
+AC_SUBST(BUILD_LVMETAD)
 AC_SUBST(CFLAGS)
 AC_SUBST(CFLOW_CMD)
 AC_SUBST(CLDFLAGS)
@@ -1274,8 +1503,11 @@ AC_SUBST(CLDWHOLEARCHIVE)
 AC_SUBST(CLUSTER)
 AC_SUBST(CLVMD)
 AC_SUBST(CLVMD_CMANAGERS)
+AC_SUBST(CLVMD_PATH)
 AC_SUBST(CMAN_CFLAGS)
 AC_SUBST(CMAN_LIBS)
+AC_SUBST(CMAP_CFLAGS)
+AC_SUBST(CMAP_LIBS)
 AC_SUBST(CMDLIB)
 AC_SUBST(CONFDB_CFLAGS)
 AC_SUBST(CONFDB_LIBS)
@@ -1291,6 +1523,7 @@ AC_SUBST(DEFAULT_BACKUP_SUBDIR)
 AC_SUBST(DEFAULT_CACHE_SUBDIR)
 AC_SUBST(DEFAULT_DATA_ALIGNMENT)
 AC_SUBST(DEFAULT_LOCK_DIR)
+AC_SUBST(DEFAULT_DM_RUN_DIR)
 AC_SUBST(DEFAULT_RUN_DIR)
 AC_SUBST(DEVMAPPER)
 AC_SUBST(DLM_CFLAGS)
@@ -1305,9 +1538,9 @@ AC_SUBST(DM_DEVICE_UID)
 AC_SUBST(DM_IOCTLS)
 AC_SUBST(DM_LIB_VERSION)
 AC_SUBST(DM_LIB_PATCHLEVEL)
+AC_SUBST(ELDFLAGS)
 AC_SUBST(FSADM)
-AC_SUBST(GULM_CFLAGS)
-AC_SUBST(GULM_LIBS)
+AC_SUBST(BLKDEACTIVATE)
 AC_SUBST(HAVE_LIBDL)
 AC_SUBST(HAVE_REALTIME)
 AC_SUBST(INTL)
@@ -1324,18 +1557,25 @@ AC_SUBST(LVM_LIBAPI)
 AC_SUBST(LVM_MAJOR)
 AC_SUBST(LVM_MINOR)
 AC_SUBST(LVM_PATCHLEVEL)
+AC_SUBST(LVM_PATH)
 AC_SUBST(LVM_RELEASE)
 AC_SUBST(LVM_RELEASE_DATE)
 AC_SUBST(MIRRORS)
-AC_SUBST(OCF)
-AC_SUBST(REPLICATORS)
 AC_SUBST(MSGFMT)
+AC_SUBST(OCF)
+AC_SUBST(OCFDIR)
 AC_SUBST(PKGCONFIG)
 AC_SUBST(POOL)
 AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PYTHON)
+AC_SUBST(PYTHON_BINDINGS)
+AC_SUBST(PYTHON_INCDIRS)
+AC_SUBST(PYTHON_LIBDIRS)
 AC_SUBST(QUORUM_CFLAGS)
 AC_SUBST(QUORUM_LIBS)
+AC_SUBST(RAID)
 AC_SUBST(READLINE_LIBS)
+AC_SUBST(REPLICATORS)
 AC_SUBST(SACKPT_CFLAGS)
 AC_SUBST(SACKPT_LIBS)
 AC_SUBST(SALCK_CFLAGS)
@@ -1346,11 +1586,19 @@ AC_SUBST(SNAPSHOTS)
 AC_SUBST(STATICDIR)
 AC_SUBST(STATIC_LINK)
 AC_SUBST(TESTING)
+AC_SUBST(THIN)
+AC_SUBST(THIN_CHECK_CMD)
 AC_SUBST(UDEV_LIBS)
 AC_SUBST(UDEV_PC)
 AC_SUBST(UDEV_RULES)
 AC_SUBST(UDEV_SYNC)
+AC_SUBST(UDEV_RULE_EXEC_DETECTION)
+AC_SUBST(UDEV_HAS_BUILTIN_BLKID)
+AC_SUBST(CUNIT_LIBS)
+AC_SUBST(CUNIT_CFLAGS)
 AC_SUBST(WRITE_INSTALL)
+AC_SUBST(DMEVENTD_PIDFILE)
+AC_SUBST(LVMETAD_PIDFILE)
 AC_SUBST(interface)
 AC_SUBST(kerneldir)
 AC_SUBST(missingkernel)
@@ -1358,6 +1606,9 @@ AC_SUBST(kernelvsn)
 AC_SUBST(tmpdir)
 AC_SUBST(udev_prefix)
 AC_SUBST(udevdir)
+AC_SUBST(systemdsystemunitdir)
+AC_SUBST(systemdutildir)
+AC_SUBST(tmpfilesdir)
 AC_SUBST(usrlibdir)
 AC_SUBST(usrsbindir)
 
@@ -1374,8 +1625,11 @@ daemons/dmeventd/Makefile
 daemons/dmeventd/libdevmapper-event.pc
 daemons/dmeventd/plugins/Makefile
 daemons/dmeventd/plugins/lvm2/Makefile
+daemons/dmeventd/plugins/raid/Makefile
 daemons/dmeventd/plugins/mirror/Makefile
 daemons/dmeventd/plugins/snapshot/Makefile
+daemons/dmeventd/plugins/thin/Makefile
+daemons/lvmetad/Makefile
 doc/Makefile
 doc/example.conf
 include/.symlinks
@@ -1387,19 +1641,37 @@ lib/locking/Makefile
 lib/mirror/Makefile
 lib/replicator/Makefile
 lib/misc/lvm-version.h
+lib/raid/Makefile
 lib/snapshot/Makefile
+lib/thin/Makefile
+libdaemon/Makefile
+libdaemon/client/Makefile
+libdaemon/server/Makefile
 libdm/Makefile
 libdm/libdevmapper.pc
 liblvm/Makefile
 liblvm/liblvm2app.pc
 man/Makefile
 po/Makefile
+python/Makefile
+python/setup.py
+scripts/blkdeactivate.sh
+scripts/blk_availability_init_red_hat
+scripts/blk_availability_systemd_red_hat.service
 scripts/clvmd_init_red_hat
 scripts/cmirrord_init_red_hat
+scripts/lvm2_lvmetad_init_red_hat
+scripts/lvm2_lvmetad_systemd_red_hat.socket
+scripts/lvm2_lvmetad_systemd_red_hat.service
 scripts/lvm2_monitoring_init_red_hat
+scripts/dm_event_systemd_red_hat.socket
+scripts/dm_event_systemd_red_hat.service
+scripts/lvm2_monitoring_systemd_red_hat.service
+scripts/lvm2_tmpfiles_red_hat.conf
 scripts/Makefile
 test/Makefile
 test/api/Makefile
+test/unit/Makefile
 tools/Makefile
 udev/Makefile
 unit-tests/datastruct/Makefile
index ce400d78a01b4dcf949282146ed1eebb65ca18a0..c83e0da052b3ff70c0157555835db53d88b3907c 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
 #
 # This file is part of LVM2.
 #
@@ -15,10 +15,14 @@ srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 top_builddir = @top_builddir@
 
-.PHONY: dmeventd clvmd cmirrord
+ifeq ("@BUILD_LVMETAD@", "yes")
+  SUBDIRS += lvmetad
+endif
+
+.PHONY: dmeventd clvmd cmirrord lvmetad
 
 ifneq ("@CLVMD@", "none")
-  SUBDIRS = clvmd
+  SUBDIRS += clvmd
 endif
 
 ifeq ("@BUILD_CMIRRORD@", "yes")
@@ -33,7 +37,7 @@ endif
 endif
 
 ifeq ($(MAKECMDGOALS),distclean)
-  SUBDIRS = clvmd cmirrord dmeventd
+  SUBDIRS = clvmd cmirrord dmeventd lvmetad
 endif
 
 include $(top_builddir)/make.tmpl
index ee19e6ceb14aee744e06cebd5330c833f0ccd375..9ca11baf148e2941b6c96f5b4428976980b42c84 100644 (file)
@@ -15,18 +15,16 @@ srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 top_builddir = @top_builddir@
 
-CCS_LIBS = @CCS_LIBS@
-CCS_CFLAGS = @CCS_CFLAGS@
 CMAN_LIBS = @CMAN_LIBS@
 CMAN_CFLAGS = @CMAN_CFLAGS@
+CMAP_LIBS = @CMAP_LIBS@
+CMAP_CFLAGS = @CMAP_CFLAGS@
 CONFDB_LIBS = @CONFDB_LIBS@
 CONFDB_CFLAGS = @CONFDB_CFLAGS@
 CPG_LIBS = @CPG_LIBS@
 CPG_CFLAGS = @CPG_CFLAGS@
 DLM_LIBS = @DLM_LIBS@
 DLM_CFLAGS = @DLM_CFLAGS@
-GULM_LIBS = @GULM_LIBS@
-GULM_CFLAGS = @GULM_CFLAGS@
 QUORUM_LIBS = @QUORUM_LIBS@
 QUORUM_CFLAGS = @QUORUM_CFLAGS@
 SALCK_LIBS = @SALCK_LIBS@
@@ -42,13 +40,6 @@ ifeq ("@DEBUG@", "yes")
        DEFS += -DDEBUG
 endif
 
-ifneq (,$(findstring gulm,, "@CLVMD@,"))
-       SOURCES += clvmd-gulm.c tcp-comms.c
-       LMLIBS += $(CCS_LIBS) $(GULM_LIBS)
-       CFLAGS += $(CCS_CFLAGS) $(GULM_CFLAGS)
-       DEFS += -DUSE_GULM
-endif
-
 ifneq (,$(findstring cman,, "@CLVMD@,"))
        SOURCES += clvmd-cman.c
        LMLIBS += $(CMAN_LIBS) $(CONFDB_LIBS) $(DLM_LIBS)
@@ -65,8 +56,8 @@ endif
 
 ifneq (,$(findstring corosync,, "@CLVMD@,"))
        SOURCES += clvmd-corosync.c
-       LMLIBS += $(CONFDB_LIBS) $(CPG_LIBS) $(DLM_LIBS) $(QUORUM_LIBS)
-       CFLAGS += $(CONFDB_CFLAGS) $(CPG_CFLAGS) $(DLM_CFLAGS) $(QUORUM_CFLAGS)
+       LMLIBS += $(CMAP_LIBS) $(CONFDB_LIBS) $(CPG_LIBS) $(DLM_LIBS) $(QUORUM_LIBS)
+       CFLAGS += $(CMAP_CFLAGS) $(CONFDB_CFLAGS) $(CPG_CFLAGS) $(DLM_CFLAGS) $(QUORUM_CFLAGS)
        DEFS += -DUSE_COROSYNC
 endif
 
@@ -76,7 +67,6 @@ ifneq (,$(findstring singlenode,, &quot;@CLVMD@,&quot;))
 endif
 
 ifeq ($(MAKECMDGOALS),distclean)
-       SOURCES += clvmd-gulm.c tcp-comms.c
        SOURCES += clvmd-cman.c
        SOURCES += clvmd-openais.c
        SOURCES += clvmd-corosync.c
index c9ea10c49d4a2022299495625e09fa2ae47fb28d..8e24f157c767016ca6350aaa2403c2307b296060 100644 (file)
@@ -30,22 +30,23 @@ struct clvm_header {
        uint16_t xid;           /* Transaction ID */
        uint32_t clientid;      /* Only used in Daemon->Daemon comms */
        int32_t  status;        /* For replies, whether request succeeded */
-       uint32_t arglen;        /* Length of argument below. 
-                                  If >1500 then it will be passed 
+       uint32_t arglen;        /* Length of argument below.
+                                  If >1500 then it will be passed
                                   around the cluster in the system LV */
        char node[1];           /* Actually a NUL-terminated string, node name.
-                                  If this is empty then the command is 
-                                  forwarded to all cluster nodes unless 
-                                  FLAG_LOCAL is also set. */
-       char args[1];           /* Arguments for the command follow the 
+                                  If this is empty then the command is
+                                  forwarded to all cluster nodes unless
+                                  FLAG_LOCAL or FLAG_REMOTE is also set. */
+       char args[1];           /* Arguments for the command follow the
                                   node name, This member is only
                                   valid if the node name is empty */
 } __attribute__ ((packed));
 
 /* Flags */
-#define CLVMD_FLAG_LOCAL        1      /* Only do this on the local node */
-#define CLVMD_FLAG_SYSTEMLV     2      /* Data in system LV under my node name */
-#define CLVMD_FLAG_NODEERRS     4       /* Reply has errors in node-specific portion */
+#define CLVMD_FLAG_LOCAL       1       /* Only do this on the local node */
+#define CLVMD_FLAG_SYSTEMLV    2       /* Data in system LV under my node name */
+#define CLVMD_FLAG_NODEERRS    4       /* Reply has errors in node-specific portion */
+#define CLVMD_FLAG_REMOTE      8       /* Do this on all nodes except for the local node */
 
 /* Name of the local socket to communicate between lvm and clvmd */
 static const char CLVMD_SOCKNAME[]= DEFAULT_RUN_DIR "/clvmd.sock";
@@ -53,7 +54,7 @@ static const char CLVMD_SOCKNAME[]= DEFAULT_RUN_DIR "/clvmd.sock";
 /* Internal commands & replies */
 #define CLVMD_CMD_REPLY    1
 #define CLVMD_CMD_VERSION  2   /* Send version around cluster when we start */
-#define CLVMD_CMD_GOAWAY   3   /* Die if received this - we are running 
+#define CLVMD_CMD_GOAWAY   3   /* Die if received this - we are running
                                   an incompatible version */
 #define CLVMD_CMD_TEST     4   /* Just for mucking about */
 
@@ -71,4 +72,11 @@ static const char CLVMD_SOCKNAME[]= DEFAULT_RUN_DIR "/clvmd.sock";
 #define CLVMD_CMD_SET_DEBUG        42
 #define CLVMD_CMD_VG_BACKUP        43
 #define CLVMD_CMD_RESTART          44
+#define CLVMD_CMD_SYNC_NAMES       45
+
+/* Used internally by some callers, but not part of the protocol.*/
+#define NODE_ALL       "*"
+#define NODE_LOCAL     "."
+#define NODE_REMOTE    "^"
+
 #endif
index 52da2acb50adc4aaad906e815ca49e1945e4ccf0..7e76dc44284638c36b1a6d33ff2e441327ad2b3a 100644 (file)
@@ -89,16 +89,17 @@ static int _init_cluster(void)
        DEBUGLOG("CMAN initialisation complete\n");
 
        /* Create a lockspace for LV & VG locks to live in */
-       lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
+       lockspace = dlm_open_lockspace(LOCKSPACE_NAME);
        if (!lockspace) {
-               if (errno == EEXIST) {
-                       lockspace = dlm_open_lockspace(LOCKSPACE_NAME);
-               }
+               lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
                if (!lockspace) {
-                       syslog(LOG_ERR, "Unable to create lockspace for CLVM: %m");
+                       syslog(LOG_ERR, "Unable to create DLM lockspace for CLVM: %m");
                        return -1;
                }
-       }
+               DEBUGLOG("Created DLM lockspace for CLVMD.\n");
+       } else
+               DEBUGLOG("Opened existing DLM lockspace for CLVMD.\n");
+
        dlm_ls_pthread_init(lockspace);
        DEBUGLOG("DLM initialisation complete\n");
        return 0;
@@ -478,6 +479,7 @@ static int _get_cluster_name(char *buf, int buflen)
 }
 
 static struct cluster_ops _cluster_cman_ops = {
+       .name                     = "cman",
        .cluster_init_completed   = _cluster_init_completed,
        .cluster_send_message     = _cluster_send_message,
        .name_from_csid           = _name_from_csid,
index 49f119719b324645a6438eacc1b20b82f82879cd..c5cd4618a31166e35e2bb47379372ff3ed9680e1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
 */
 
 #include "clvmd-common.h"
-
-#include <pthread.h>
-
 #include "clvmd-comms.h"
 #include "clvm.h"
 #include "clvmd.h"
+#include "lvm-globals.h"
 #include "lvm-functions.h"
 
 #include "locking.h"
 
 #include <sys/utsname.h>
 
-extern debug_t debug;
 extern struct cluster_ops *clops;
 static int restart_clvmd(void);
 
@@ -81,6 +78,9 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
        unsigned char lock_cmd;
        unsigned char lock_flags;
 
+       /* Reset test mode before we start */
+       init_test(0);
+
        /* Do the command */
        switch (msg->cmd) {
                /* Just a test message */
@@ -96,7 +96,9 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
                        *buf = new_buf;
                }
                if (*buf) {
-                       uname(&nodeinfo);
+                       if (uname(&nodeinfo))
+                               memset(&nodeinfo, 0, sizeof(nodeinfo));
+
                        *retlen = 1 + dm_snprintf(*buf, buflen,
                                                  "TEST from %s: %s v%s",
                                                  nodeinfo.nodename, args,
@@ -110,14 +112,18 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
                lockname = &args[2];
                /* Check to see if the VG is in use by LVM1 */
                status = do_check_lvm1(lockname);
+               if (lock_flags & LCK_TEST_MODE)
+                       init_test(1);
                do_lock_vg(lock_cmd, lock_flags, lockname);
                break;
 
        case CLVMD_CMD_LOCK_LV:
                /* This is the biggie */
-               lock_cmd = args[0] & (LCK_NONBLOCK | LCK_HOLD | LCK_SCOPE_MASK | LCK_TYPE_MASK);
+               lock_cmd = args[0];
                lock_flags = args[1];
                lockname = &args[2];
+               if (lock_flags & LCK_TEST_MODE)
+                       init_test(1);
                status = do_lock_lv(lock_cmd, lock_flags, lockname);
                /* Replace EIO with something less scary */
                if (status == EIO) {
@@ -139,12 +145,16 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
                do_refresh_cache();
                break;
 
+       case CLVMD_CMD_SYNC_NAMES:
+               lvm_do_fs_unlock();
+               break;
+
        case CLVMD_CMD_SET_DEBUG:
-               debug = args[0];
+               clvmd_set_debug((debug_t) args[0]);
                break;
 
        case CLVMD_CMD_RESTART:
-               restart_clvmd();
+               status = restart_clvmd();
                break;
 
        case CLVMD_CMD_GET_CLUSTERNAME:
@@ -182,7 +192,6 @@ static int lock_vg(struct local_client *client)
     struct clvm_header *header =
        (struct clvm_header *) client->bits.localsock.cmd;
     unsigned char lock_cmd;
-    unsigned char lock_flags;
     int lock_mode;
     char *args = header->node + strlen(header->node) + 1;
     int lkid;
@@ -204,7 +213,7 @@ static int lock_vg(struct local_client *client)
 
     lock_cmd = args[0] & (LCK_NONBLOCK | LCK_HOLD | LCK_SCOPE_MASK | LCK_TYPE_MASK);
     lock_mode = ((int)lock_cmd & LCK_TYPE_MASK);
-    lock_flags = args[1];
+    /* lock_flags = args[1]; */
     lockname = &args[2];
     DEBUGLOG("doing PRE command LOCK_VG '%s' at %x (client=%p)\n", lockname, lock_cmd, client);
 
@@ -228,7 +237,8 @@ static int lock_vg(struct local_client *client)
        if (status)
            status = errno;
        else
-           dm_hash_insert(lock_hash, lockname, (void *)(long)lkid);
+           if (!dm_hash_insert(lock_hash, lockname, (void *)(long)lkid))
+                    return ENOMEM;
     }
 
     return status;
@@ -245,10 +255,11 @@ int do_pre_command(struct local_client *client)
        unsigned char lock_cmd;
        unsigned char lock_flags;
        char *args = header->node + strlen(header->node) + 1;
-       int lockid;
+       int lockid = 0;
        int status = 0;
        char *lockname;
 
+       init_test(0);
        switch (header->cmd) {
        case CLVMD_CMD_TEST:
                status = sync_lock("CLVMD_TEST", LCK_EXCL, 0, &lockid);
@@ -267,6 +278,8 @@ int do_pre_command(struct local_client *client)
                lock_cmd = args[0];
                lock_flags = args[1];
                lockname = &args[2];
+               if (lock_flags & LCK_TEST_MODE)
+                       init_test(1);
                status = pre_lock_lv(lock_cmd, lock_flags, lockname);
                break;
 
@@ -274,6 +287,7 @@ int do_pre_command(struct local_client *client)
        case CLVMD_CMD_GET_CLUSTERNAME:
        case CLVMD_CMD_SET_DEBUG:
        case CLVMD_CMD_VG_BACKUP:
+       case CLVMD_CMD_SYNC_NAMES:
        case CLVMD_CMD_LOCK_QUERY:
        case CLVMD_CMD_RESTART:
                break;
@@ -297,6 +311,7 @@ int do_post_command(struct local_client *client)
        char *args = header->node + strlen(header->node) + 1;
        char *lockname;
 
+       init_test(0);
        switch (header->cmd) {
        case CLVMD_CMD_TEST:
                status =
@@ -304,18 +319,18 @@ int do_post_command(struct local_client *client)
                client->bits.localsock.private = 0;
                break;
 
-       case CLVMD_CMD_LOCK_VG:
-       case CLVMD_CMD_VG_BACKUP:
-       case CLVMD_CMD_LOCK_QUERY:
-               /* Nothing to do here */
-               break;
-
        case CLVMD_CMD_LOCK_LV:
                lock_cmd = args[0];
                lock_flags = args[1];
                lockname = &args[2];
+               if (lock_flags & LCK_TEST_MODE)
+                       init_test(1);
                status = post_lock_lv(lock_cmd, lock_flags, lockname);
                break;
+
+       default:
+               /* Nothing to do here */
+               break;
        }
        return status;
 }
@@ -324,90 +339,93 @@ int do_post_command(struct local_client *client)
 /* Called when the client is about to be deleted */
 void cmd_client_cleanup(struct local_client *client)
 {
-    if (client->bits.localsock.private) {
-
        struct dm_hash_node *v;
-       struct dm_hash_table *lock_hash =
-           (struct dm_hash_table *)client->bits.localsock.private;
+       struct dm_hash_table *lock_hash;
+       int lkid;
+       char *lockname;
 
-       dm_hash_iterate(v, lock_hash) {
-               int lkid = (int)(long)dm_hash_get_data(lock_hash, v);
-               char *lockname = dm_hash_get_key(lock_hash, v);
+       if (!client->bits.localsock.private)
+               return;
 
+       lock_hash = (struct dm_hash_table *)client->bits.localsock.private;
+
+       dm_hash_iterate(v, lock_hash) {
+               lkid = (int)(long)dm_hash_get_data(lock_hash, v);
+               lockname = dm_hash_get_key(lock_hash, v);
                DEBUGLOG("cleanup: Unlocking lock %s %x\n", lockname, lkid);
-               sync_unlock(lockname, lkid);
+               (void) sync_unlock(lockname, lkid);
        }
 
        dm_hash_destroy(lock_hash);
        client->bits.localsock.private = 0;
-    }
 }
 
 
 static int restart_clvmd(void)
 {
-       char **argv = NULL;
-       char *debug_arg = NULL, *lv_name;
-       int i, argc = 0, max_locks = 0;
+       const char **argv;
+       char *lv_name;
+       int argc = 0, max_locks = 0;
        struct dm_hash_node *hn = NULL;
+       char debug_arg[16];
+       const char *clvmd = getenv("LVM_CLVMD_BINARY") ? : CLVMD_PATH;
 
        DEBUGLOG("clvmd restart requested\n");
 
        /* Count exclusively-open LVs */
-       hn = NULL;
        do {
                hn = get_next_excl_lock(hn, &lv_name);
-               if (lv_name)
+               if (lv_name) {
                        max_locks++;
-       } while (hn && *lv_name);
+                       if (!*lv_name)
+                               break; /* FIXME: Is this error ? */
+               }
+       } while (hn);
 
        /* clvmd + locks (-E uuid) + debug (-d X) + NULL */
-       argv = malloc((max_locks * 2 + 4) * sizeof(*argv));
-       if (!argv)
+       if (!(argv = malloc((max_locks * 2 + 5) * sizeof(*argv))))
                goto_out;
 
        /*
         * Build the command-line
         */
-       argv[argc++] = strdup("clvmd");
-       if (!argv[0])
-               goto_out;
+       argv[argc++] = "clvmd";
 
        /* Propogate debug options */
-       if (debug) {
-               if (!(debug_arg = malloc(16)) ||
-                   dm_snprintf(debug_arg, 16, "-d%d", (int)debug) < 0)
+       if (clvmd_get_debug()) {
+               if (dm_snprintf(debug_arg, sizeof(debug_arg), "-d%u", clvmd_get_debug()) < 0)
                        goto_out;
                argv[argc++] = debug_arg;
        }
 
+       argv[argc++] = "-I";
+       argv[argc++] = clops->name;
+
        /* Now add the exclusively-open LVs */
+       hn = NULL;
        do {
                hn = get_next_excl_lock(hn, &lv_name);
                if (lv_name) {
-                       argv[argc] = strdup("-E");
-                       if (!argv[argc++])
-                               goto_out;
-                       argv[argc] = strdup(lv_name);
-                       if (!argv[argc++])
-                               goto_out;
-
+                       if (!*lv_name)
+                               break; /* FIXME: Is this error ? */
+                       argv[argc++] = "-E";
+                       argv[argc++] = lv_name;
                        DEBUGLOG("excl lock: %s\n", lv_name);
-                       hn = get_next_excl_lock(hn, &lv_name);
                }
-       } while (hn && *lv_name);
-       argv[argc++] = NULL;
+       } while (hn);
+       argv[argc] = NULL;
 
        /* Exec new clvmd */
+       DEBUGLOG("--- Restarting %s ---\n", clvmd);
+       for (argc = 1; argv[argc]; argc++) DEBUGLOG("--- %d: %s\n", argc, argv[argc]);
+
        /* NOTE: This will fail when downgrading! */
-       execve(CLVMD_PATH, argv, NULL);
+       execvp(clvmd, (char **)argv);
 out:
        /* We failed */
        DEBUGLOG("Restart of clvmd failed.\n");
 
-       for (i = 0; i < argc && argv[i]; i++)
-               free(argv[i]);
        free(argv);
 
-       return 0;
+       return EIO;
 }
index fbcfe8b540730d3e7ad329e927270670bc57c083..7207334ec4fdca77cf542303bbc2083ac516ec63 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -23,6 +23,7 @@
 struct local_client;
 
 struct cluster_ops {
+       const char *name;
        void (*cluster_init_completed) (void);
 
        int (*cluster_send_message) (const void *buf, int msglen,
@@ -54,13 +55,6 @@ struct cluster_ops {
 
 };
 
-#ifdef USE_GULM
-#  include "tcp-comms.h"
-struct cluster_ops *init_gulm_cluster(void);
-#define MAX_CSID_LEN                   GULM_MAX_CSID_LEN
-#define MAX_CLUSTER_MEMBER_NAME_LEN    GULM_MAX_CLUSTER_MEMBER_NAME_LEN
-#endif
-
 #ifdef USE_CMAN
 #  include <netinet/in.h>
 #  include "libcman.h"
index cfe71502bd25a4dd8f752fce84306787ea5464b5..d85ec1e61b66a3274bf7b0929aa2ad96582fdcec 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2009-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
 
 #include <corosync/cpg.h>
 #include <corosync/quorum.h>
-#include <corosync/confdb.h>
+
+#ifdef HAVE_COROSYNC_CONFDB_H
+#  include <corosync/confdb.h>
+#elif defined HAVE_COROSYNC_CMAP_H
+#  include <corosync/cmap.h>
+#else
+#  error "Either HAVE_COROSYNC_CONFDB_H or HAVE_COROSYNC_CMAP_H must be defined."
+#endif
+
 #include <libdlm.h>
 
 #include <syslog.h>
@@ -274,6 +282,10 @@ static int _init_cluster(void)
 {
        cs_error_t err;
 
+#ifdef QUORUM_SET      /* corosync/quorum.h */
+       uint32_t quorum_type;
+#endif
+
        node_hash = dm_hash_create(100);
 
        err = cpg_initialize(&cpg_handle,
@@ -285,8 +297,21 @@ static int _init_cluster(void)
                return cs_to_errno(err);
        }
 
+#ifdef QUORUM_SET
+       err = quorum_initialize(&quorum_handle,
+                               &quorum_callbacks,
+                               &quorum_type);
+
+       if (quorum_type != QUORUM_SET) {
+               syslog(LOG_ERR, "Corosync quorum service is not configured");
+               DEBUGLOG("Corosync quorum service is not configured");
+               return EINVAL;
+       }
+#else
        err = quorum_initialize(&quorum_handle,
                                &quorum_callbacks);
+#endif
+
        if (err != CS_OK) {
                syslog(LOG_ERR, "Cannot initialise Corosync quorum service: %d",
                       err);
@@ -294,19 +319,18 @@ static int _init_cluster(void)
                return cs_to_errno(err);
        }
 
-
        /* Create a lockspace for LV & VG locks to live in */
-       lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
+       lockspace = dlm_open_lockspace(LOCKSPACE_NAME);
        if (!lockspace) {
-               if (errno == EEXIST) {
-                       lockspace = dlm_open_lockspace(LOCKSPACE_NAME);
-               }
+               lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
                if (!lockspace) {
-                       syslog(LOG_ERR, "Unable to create lockspace for CLVM: %m");
-                       quorum_finalize(quorum_handle);
+                       syslog(LOG_ERR, "Unable to create DLM lockspace for CLVM: %m");
                        return -1;
                }
-       }
+               DEBUGLOG("Created DLM lockspace for CLVMD.\n");
+       } else
+               DEBUGLOG("Opened existing DLM lockspace for CLVMD.\n");
+
        dlm_ls_pthread_init(lockspace);
        DEBUGLOG("DLM initialisation complete\n");
 
@@ -552,6 +576,7 @@ static int _cluster_send_message(const void *buf, int msglen, const char *csid,
        return cs_to_errno(err);
 }
 
+#ifdef HAVE_COROSYNC_CONFDB_H
 /*
  * We are not necessarily connected to a Red Hat Cluster system,
  * but if we are, this returns the cluster name from cluster.conf.
@@ -598,7 +623,40 @@ out:
        return 0;
 }
 
+#elif defined HAVE_COROSYNC_CMAP_H
+
+static int _get_cluster_name(char *buf, int buflen)
+{
+       cmap_handle_t cmap_handle = 0;
+       int result;
+       char *name = NULL;
+
+       /* This is a default in case everything else fails */
+       strncpy(buf, "Corosync", buflen);
+
+       /* Look for a cluster name in cmap */
+       result = cmap_initialize(&cmap_handle);
+       if (result != CS_OK)
+               return 0;
+
+       result = cmap_get_string(cmap_handle, "totem.cluster_name", &name);
+       if (result != CS_OK)
+               goto out;
+
+       memset(buf, 0, buflen);
+       strncpy(buf, name, buflen - 1);
+
+out:
+       if (name)
+               free(name);
+       cmap_finalize(cmap_handle);
+       return 0;
+}
+
+#endif
+
 static struct cluster_ops _cluster_corosync_ops = {
+       .name                     = "corosync",
        .cluster_init_completed   = NULL,
        .cluster_send_message     = _cluster_send_message,
        .name_from_csid           = _name_from_csid,
diff --git a/daemons/clvmd/clvmd-gulm.c b/daemons/clvmd/clvmd-gulm.c
deleted file mode 100644 (file)
index 3561004..0000000
+++ /dev/null
@@ -1,1010 +0,0 @@
-/*
- * Copyright (C) 2002-2003 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU Lesser General Public License v.2.1.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/*
- * This provides the interface between clvmd and gulm as the cluster
- * and lock manager.
- *
- * It also provides the "liblm" functions too as it's hard (and pointless)
- * to seperate them out when using gulm.
- *
- * What it does /not/ provide is the communications between clvmd daemons
- * on the cluster nodes. That is done in tcp-comms.c
- */
-
-#include "clvmd-common.h"
-
-#include <pthread.h>
-#include <sys/utsname.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/file.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <stdint.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <utmpx.h>
-#include <syslog.h>
-#include <assert.h>
-#include <ccs.h>
-#include <libgulm.h>
-
-#include "locking.h"
-#include "clvm.h"
-#include "clvmd-comms.h"
-#include "lvm-functions.h"
-#include "clvmd.h"
-#include "clvmd-gulm.h"
-
-/* Hash list of nodes in the cluster */
-static struct dm_hash_table *node_hash;
-
-/* hash list of outstanding lock requests */
-static struct dm_hash_table *lock_hash;
-
-/* Copy of the current quorate state */
-static uint8_t gulm_quorate = 0;
-static enum {INIT_NOTDONE, INIT_DONE, INIT_WAITQUORATE} init_state = INIT_NOTDONE;
-
-/* Number of active nodes */
-static int num_nodes;
-
-static char *cluster_name;
-static int in_shutdown = 0;
-
-static pthread_mutex_t lock_start_mutex;
-static volatile int lock_start_flag;
-
-struct node_info
-{
-    enum {NODE_UNKNOWN, NODE_DOWN, NODE_UP, NODE_CLVMD} state;
-    char name[GULM_MAX_CLUSTER_MEMBER_NAME_LEN];
-};
-
-struct lock_wait
-{
-    pthread_cond_t cond;
-    pthread_mutex_t mutex;
-    int status;
-};
-
-/* Forward */
-static int read_from_core_sock(struct local_client *client, char *buf, int len, const char *csid,
-                              struct local_client **new_client);
-static int read_from_lock_sock(struct local_client *client, char *buf, int len, const char *csid,
-                              struct local_client **new_client);
-static int get_all_cluster_nodes(void);
-static int _csid_from_name(char *csid, const char *name);
-static void _cluster_closedown(void);
-
-/* In tcp-comms.c */
-extern struct dm_hash_table *sock_hash;
-
-static int add_internal_client(int fd, fd_callback_t callback)
-{
-    struct local_client *client;
-
-    DEBUGLOG("Add_internal_client, fd = %d\n", fd);
-
-    /* Add a GULM file descriptor it to the main loop */
-    client = malloc(sizeof(struct local_client));
-    if (!client)
-    {
-       DEBUGLOG("malloc failed\n");
-       return -1;
-    }
-
-    memset(client, 0, sizeof(struct local_client));
-    client->fd = fd;
-    client->type = CLUSTER_INTERNAL;
-    client->callback = callback;
-    add_client(client);
-
-    /* Set Close-on-exec */
-    fcntl(fd, F_SETFD, 1);
-
-    return 0;
-}
-
-/* Gulm library handle */
-static gulm_interface_p gulm_if;
-static lg_core_callbacks_t core_callbacks;
-static lg_lockspace_callbacks_t lock_callbacks;
-
-static void badsig_handler(int sig)
-{
-    DEBUGLOG("got sig %d\n", sig);
-    _cluster_closedown();
-    exit(0);
-}
-
-static void _reread_config(void)
-{
-        /* Re-read CCS node list */
-       DEBUGLOG("Re-reading CCS config\n");
-       get_all_cluster_nodes();
-}
-
-static int _init_cluster(void)
-{
-    int status;
-    int ccs_h;
-    int port = 0;
-    char *portstr;
-
-    /* Get cluster name from CCS */
-    ccs_h = ccs_force_connect(NULL, 0);
-    if (ccs_h < 0)
-    {
-       syslog(LOG_ERR, "Cannot login in to CCSD server\n");
-       return -1;
-    }
-
-    ccs_get(ccs_h, "//cluster/@name", &cluster_name);
-    DEBUGLOG("got cluster name %s\n", cluster_name);
-
-    if (!ccs_get(ccs_h, "//cluster/clvm/@port", &portstr))
-    {
-       port = atoi(portstr);
-       free(portstr);
-       DEBUGLOG("got port number %d\n", port);
-
-       if (port <= 0 && port >= 65536)
-           port = 0;
-    }
-
-    ccs_disconnect(ccs_h);
-
-    /* Block locking until we are logged in */
-    pthread_mutex_init(&lock_start_mutex, NULL);
-    pthread_mutex_lock(&lock_start_mutex);
-    lock_start_flag = 1;
-
-    node_hash = dm_hash_create(100);
-    lock_hash = dm_hash_create(10);
-
-    /* Get all nodes from CCS */
-    if (get_all_cluster_nodes())
-       return -1;
-
-    /* Initialise GULM library */
-    status = lg_initialize(&gulm_if, cluster_name, "clvmd");
-    if (status)
-    {
-       DEBUGLOG("lg_initialize failed: %d\n", status);
-       return status;
-    }
-
-    /* Connect to core - we are not "important" :-) */
-    status = lg_core_login(gulm_if, 0);
-    if (status)
-    {
-       DEBUGLOG("lg_core_login failed: %d\n", status);
-       return status;
-    }
-
-    /* Initialise the inter-node comms */
-    status = init_comms(port);
-    if (status)
-       return status;
-
-    /* Add core FD to the list */
-    status = add_internal_client(lg_core_selector(gulm_if), read_from_core_sock);
-    if (status)
-    {
-       DEBUGLOG("can't allocate client space\n");
-       return status;
-    }
-
-    /* Connect to the lock server */
-    if (lg_lock_login(gulm_if, "CLVM"))
-    {
-       syslog(LOG_ERR, "Cannot login in to LOCK server\n");
-       DEBUGLOG("Cannot login in to LOCK server\n");
-       exit(88);
-    }
-
-    /* Add lockspace FD to the list */
-    status = add_internal_client(lg_lock_selector(gulm_if), read_from_lock_sock);
-    if (status)
-    {
-       DEBUGLOG("can't allocate client space\n");
-       exit(status);
-    }
-
-    /* Request a list of nodes, we can't really do anything until
-       this comes back */
-    status = lg_core_nodelist(gulm_if);
-    if (status)
-    {
-       DEBUGLOG("lg_core_nodelist failed: %d\n", status);
-       return status;
-    }
-
-    /* So I can kill it without taking GULM down too */
-    signal(SIGINT, badsig_handler);
-    signal(SIGTERM, badsig_handler);
-
-    return 0;
-}
-
-static void _cluster_closedown(void)
-{
-    DEBUGLOG("cluster_closedown\n");
-    in_shutdown = 1;
-    destroy_lvhash();
-    lg_lock_logout(gulm_if);
-    lg_core_logout(gulm_if);
-    lg_release(gulm_if);
-}
-
-/* Expire locks for a named node, or us */
-#define GIO_KEY_SIZE 46
-static void drop_expired_locks(char *nodename)
-{
-    struct utsname nodeinfo;
-    uint8_t mask[GIO_KEY_SIZE];
-
-    DEBUGLOG("Dropping expired locks for %s\n", nodename?nodename:"(null)");
-    memset(mask, 0xff, GIO_KEY_SIZE);
-
-    if (!nodename)
-    {
-       uname(&nodeinfo);
-       nodename = nodeinfo.nodename;
-    }
-
-    if (lg_lock_drop_exp(gulm_if, nodename, mask, GIO_KEY_SIZE))
-    {
-       DEBUGLOG("Error calling lg_lock_drop_exp()\n");
-    }
-}
-
-
-static int read_from_core_sock(struct local_client *client, char *buf, int len, const char *csid,
-                              struct local_client **new_client)
-{
-    int status;
-
-    *new_client = NULL;
-    status = lg_core_handle_messages(gulm_if, &core_callbacks, NULL);
-    return status<0 ? status : 1;
-}
-
-static int read_from_lock_sock(struct local_client *client, char *buf, int len, const char *csid,
-                              struct local_client **new_client)
-{
-    int status;
-
-    *new_client = NULL;
-    status = lg_lock_handle_messages(gulm_if, &lock_callbacks, NULL);
-    return status<0 ? status : 1;
-}
-
-
-/* CORE callback routines */
-static int core_login_reply(void *misc, uint64_t gen, uint32_t error, uint32_t rank, uint8_t corestate)
-{
-   DEBUGLOG("CORE Got a Login reply.  gen:%lld err:%d rank:%d corestate:%d\n",
-         gen, error, rank, corestate);
-
-   if (error)
-       exit(error);
-
-   /* Get the current core state (for quorum) */
-   lg_core_corestate(gulm_if);
-
-   return 0;
-}
-
-static void set_node_state(struct node_info *ninfo, char *csid, uint8_t nodestate)
-{
-    if (nodestate == lg_core_Logged_in)
-    {
-       /* Don't clobber NODE_CLVMD state */
-       if (ninfo->state != NODE_CLVMD)
-       {
-           if (ninfo->state == NODE_UNKNOWN ||
-               ninfo->state == NODE_DOWN)
-               num_nodes++;
-
-           ninfo->state = NODE_UP;
-       }
-    }
-    else
-    {
-       if (nodestate == lg_core_Expired ||
-           nodestate == lg_core_Fenced ||
-           nodestate == lg_core_Logged_out)
-       {
-           if (ninfo->state != NODE_DOWN)
-               num_nodes--;
-           ninfo->state = NODE_DOWN;
-       }
-    }
-    /* Gulm doesn't always send node DOWN events, so even if this a a node UP we must
-     * assume (ahem) that it prevously went down at some time. So we close
-     * the sockets here to make sure that we don't have any dead connections
-     * to that node.
-     */
-    tcp_remove_client(csid);
-
-    DEBUGLOG("set_node_state, '%s' state = %d num_nodes=%d\n",
-            ninfo->name, ninfo->state, num_nodes);
-}
-
-static struct node_info *add_or_set_node(char *name, struct in6_addr *ip, uint8_t state)
-{
-    struct node_info *ninfo;
-
-    ninfo = dm_hash_lookup_binary(node_hash, (char *)ip, GULM_MAX_CSID_LEN);
-    if (!ninfo)
-    {
-       /* If we can't find that node then re-read the config file in case it
-          was added after we were started */
-       DEBUGLOG("Node %s not found, re-reading config file\n", name);
-       get_all_cluster_nodes();
-
-       /* Now try again */
-       ninfo = dm_hash_lookup_binary(node_hash, (char *)ip, GULM_MAX_CSID_LEN);
-       if (!ninfo)
-       {
-           DEBUGLOG("Ignoring node %s, not part of the SAN cluster\n", name);
-           return NULL;
-       }
-    }
-
-    set_node_state(ninfo, (char *)ip, state);
-
-    return ninfo;
-}
-
-static void _get_our_csid(char *csid)
-{
-       get_our_gulm_csid(csid);
-}
-
-static int core_nodelist(void *misc, lglcb_t type, char *name, struct in6_addr *ip, uint8_t state)
-{
-    DEBUGLOG("CORE nodelist\n");
-
-    if (type == lglcb_start)
-    {
-       DEBUGLOG("Got Nodelist, start\n");
-    }
-    else
-    {
-       if (type == lglcb_item)
-       {
-           DEBUGLOG("Got nodelist, item: %s, %#x\n", name, state);
-
-           add_or_set_node(name, ip, state);
-       }
-       else
-       {
-           if (type == lglcb_stop)
-           {
-               char ourcsid[GULM_MAX_CSID_LEN];
-
-               DEBUGLOG("Got Nodelist, stop\n");
-               if (gulm_quorate)
-               {
-                       clvmd_cluster_init_completed();
-                       init_state = INIT_DONE;
-               }
-               else
-               {
-                       if (init_state == INIT_NOTDONE)
-                               init_state = INIT_WAITQUORATE;
-               }
-
-               /* Mark ourself as up */
-               _get_our_csid(ourcsid);
-               gulm_add_up_node(ourcsid);
-           }
-           else
-           {
-               DEBUGLOG("Unknown lglcb_t %#x\n", type);
-           }
-       }
-    }
-
-    return 0;
-}
-
-static int core_statechange(void *misc, uint8_t corestate, uint8_t quorate, struct in6_addr *masterip, char *mastername)
-{
-    DEBUGLOG("CORE Got statechange. quorate:%d, corestate:%x mastername:%s\n",
-            quorate, corestate, mastername);
-
-    gulm_quorate = quorate;
-    if (quorate && init_state == INIT_WAITQUORATE)
-    {
-           clvmd_cluster_init_completed();
-           init_state = INIT_DONE;
-    }
-    return 0;
-}
-
-static int core_nodechange(void *misc, char *nodename, struct in6_addr *nodeip, uint8_t nodestate)
-{
-    struct node_info *ninfo;
-
-    DEBUGLOG("CORE node change, name=%s, state = %d\n", nodename, nodestate);
-
-    /* If we don't get nodeip here, try a lookup by name */
-    if (!nodeip)
-       _csid_from_name((char *)nodeip, nodename);
-    if (!nodeip)
-       return 0;
-
-    ninfo = add_or_set_node(nodename, nodeip, nodestate);
-    if (!ninfo)
-       return 0;
-
-    /* Check if we need to drop any expired locks */
-    if (ninfo->state == NODE_DOWN)
-    {
-       drop_expired_locks(nodename);
-    }
-
-    return 0;
-}
-static int core_error(void *misc, uint32_t err)
-{
-    DEBUGLOG("CORE error: %d\n", err);
-    // Not sure what happens here
-    return 0;
-}
-
-/* LOCK callback routines */
-static int lock_login_reply(void *misc, uint32_t error, uint8_t which)
-{
-    DEBUGLOG("LOCK Got a Login reply.  err:%d which:%d\n",
-            error, which);
-
-    if (error)
-       exit(error);
-
-    /* Drop any expired locks for us that might be hanging around */
-    drop_expired_locks(NULL);
-
-    /* Enable locking operations in other threads */
-    if (lock_start_flag)
-    {
-       lock_start_flag = 0;
-       pthread_mutex_unlock(&lock_start_mutex);
-    }
-
-    return 0;
-}
-
-static int lock_lock_state(void *misc, uint8_t *key, uint16_t keylen,
-                          uint64_t subid, uint64_t start, uint64_t stop,
-                          uint8_t state, uint32_t flags, uint32_t error,
-                          uint8_t *LVB, uint16_t LVBlen)
-{
-    struct lock_wait *lwait;
-
-    DEBUGLOG("LOCK lock state: %s, error = %d\n", key, error);
-
-    /* No waiting process to wake up when we are shutting down */
-    if (in_shutdown)
-           return 0;
-
-    lwait = dm_hash_lookup(lock_hash, key);
-    if (!lwait)
-    {
-       DEBUGLOG("Can't find hash entry for resource %s\n", key);
-       return 0;
-    }
-    lwait->status = error;
-    pthread_mutex_lock(&lwait->mutex);
-    pthread_cond_signal(&lwait->cond);
-    pthread_mutex_unlock(&lwait->mutex);
-
-    return 0;
-}
-static int lock_error(void *misc, uint32_t err)
-{
-    DEBUGLOG("LOCK error: %d\n", err);
-    // Not sure what happens here
-    return 0;
-}
-
-
-/* CORE callbacks */
-static lg_core_callbacks_t core_callbacks = {
-    .login_reply  = core_login_reply,
-    .nodelist     = core_nodelist,
-    .statechange  = core_statechange,
-    .nodechange   = core_nodechange,
-    .error        = core_error,
-};
-
-/* LOCK callbacks */
-static lg_lockspace_callbacks_t lock_callbacks = {
-    .login_reply   = lock_login_reply,
-    .lock_state    = lock_lock_state,
-    .error         = lock_error,
-};
-
-/* Allow tcp-comms to loop round the list of active nodes */
-int get_next_node_csid(void **context, char *csid)
-{
-    struct node_info *ninfo = NULL;
-
-    /* First node */
-    if (!*context)
-    {
-       *context = dm_hash_get_first(node_hash);
-    }
-    else
-    {
-       *context = dm_hash_get_next(node_hash, *context);
-    }
-    if (*context)
-       ninfo = dm_hash_get_data(node_hash, *context);
-
-    /* Find a node that is UP */
-    while (*context && ninfo->state == NODE_DOWN)
-    {
-       *context = dm_hash_get_next(node_hash, *context);
-       if (*context)
-       {
-           ninfo = dm_hash_get_data(node_hash, *context);
-       }
-    }
-
-    if (!*context || ninfo->state == NODE_DOWN)
-    {
-       return 0;
-    }
-
-    memcpy(csid, dm_hash_get_key(node_hash, *context), GULM_MAX_CSID_LEN);
-    return 1;
-}
-
-int gulm_name_from_csid(const char *csid, char *name)
-{
-    struct node_info *ninfo;
-
-    ninfo = dm_hash_lookup_binary(node_hash, csid, GULM_MAX_CSID_LEN);
-    if (!ninfo)
-    {
-        sprintf(name, "UNKNOWN %s", print_csid(csid));
-       return -1;
-    }
-
-    strcpy(name, ninfo->name);
-    return 0;
-}
-
-
-static int _csid_from_name(char *csid, const char *name)
-{
-    struct dm_hash_node *hn;
-    struct node_info *ninfo;
-
-    dm_hash_iterate(hn, node_hash)
-    {
-       ninfo = dm_hash_get_data(node_hash, hn);
-       if (strcmp(ninfo->name, name) == 0)
-       {
-           memcpy(csid, dm_hash_get_key(node_hash, hn), GULM_MAX_CSID_LEN);
-           return 0;
-       }
-    }
-    return -1;
-}
-
-static int _get_num_nodes()
-{
-    DEBUGLOG("num_nodes = %d\n", num_nodes);
-    return num_nodes;
-}
-
-/* Node is now known to be running a clvmd */
-void gulm_add_up_node(const char *csid)
-{
-    struct node_info *ninfo;
-
-    ninfo = dm_hash_lookup_binary(node_hash, csid, GULM_MAX_CSID_LEN);
-    if (!ninfo) {
-           DEBUGLOG("gulm_add_up_node no node_hash entry for csid %s\n", print_csid(csid));
-       return;
-    }
-
-    DEBUGLOG("gulm_add_up_node %s\n", ninfo->name);
-
-    if (ninfo->state == NODE_DOWN)
-           num_nodes++;
-    ninfo->state = NODE_CLVMD;
-
-    return;
-
-}
-/* Node is now known to be NOT running a clvmd */
-void add_down_node(char *csid)
-{
-    struct node_info *ninfo;
-
-    ninfo = dm_hash_lookup_binary(node_hash, csid, GULM_MAX_CSID_LEN);
-    if (!ninfo)
-       return;
-
-    /* Only set it to UP if it was previously known to be
-       running clvmd - gulm may set it DOWN quite soon */
-    if (ninfo->state == NODE_CLVMD)
-       ninfo->state = NODE_UP;
-    drop_expired_locks(ninfo->name);
-    return;
-
-}
-
-/* Call a callback for each node, so the caller knows whether it's up or down */
-static int _cluster_do_node_callback(struct local_client *master_client,
-                                    void (*callback)(struct local_client *, const char *csid, int node_up))
-{
-    struct dm_hash_node *hn;
-    struct node_info *ninfo;
-    int somedown = 0;
-
-    dm_hash_iterate(hn, node_hash)
-    {
-       char csid[GULM_MAX_CSID_LEN];
-       struct local_client *client;
-
-       ninfo = dm_hash_get_data(node_hash, hn);
-       memcpy(csid, dm_hash_get_key(node_hash, hn), GULM_MAX_CSID_LEN);
-
-       DEBUGLOG("down_callback. node %s, state = %d\n", ninfo->name, ninfo->state);
-
-       client = dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
-       if (!client)
-       {
-           /* If it's up but not connected, try to make contact */
-           if (ninfo->state == NODE_UP)
-                   gulm_connect_csid(csid, &client);
-
-           client = dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
-
-       }
-       DEBUGLOG("down_callback2. node %s, state = %d\n", ninfo->name, ninfo->state);
-       if (ninfo->state != NODE_DOWN)
-               callback(master_client, csid, ninfo->state == NODE_CLVMD);
-
-       if (ninfo->state != NODE_CLVMD)
-               somedown = -1;
-    }
-    return somedown;
-}
-
-/* Convert gulm error codes to unix errno numbers */
-static int gulm_to_errno(int gulm_ret)
-{
-    switch (gulm_ret)
-    {
-    case lg_err_TryFailed:
-    case lg_err_AlreadyPend:
-           errno = EAGAIN;
-           break;
-
-       /* More?? */
-    default:
-           errno = EINVAL;
-    }
-
-    return gulm_ret ? -1 : 0;
-}
-
-/* Real locking */
-static int _lock_resource(char *resource, int mode, int flags, int *lockid)
-{
-    int status;
-    struct lock_wait lwait;
-
-    /* Wait until the lock module is ready */
-    if (lock_start_flag)
-    {
-       pthread_mutex_lock(&lock_start_mutex);
-       pthread_mutex_unlock(&lock_start_mutex);
-    }
-
-    pthread_cond_init(&lwait.cond, NULL);
-    pthread_mutex_init(&lwait.mutex, NULL);
-    pthread_mutex_lock(&lwait.mutex);
-
-    /* This needs to be converted from DLM/LVM2 value for GULM */
-    if (flags & LCKF_NOQUEUE) flags = lg_lock_flag_Try;
-
-    dm_hash_insert(lock_hash, resource, &lwait);
-    DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
-
-    status = lg_lock_state_req(gulm_if, resource, strlen(resource)+1,
-                              0, 0, 0,
-                              mode, flags, NULL, 0);
-    if (status)
-    {
-       DEBUGLOG("lg_lock_state returned %d\n", status);
-       return status;
-    }
-
-    /* Wait for it to complete */
-    pthread_cond_wait(&lwait.cond, &lwait.mutex);
-    pthread_mutex_unlock(&lwait.mutex);
-
-    dm_hash_remove(lock_hash, resource);
-    DEBUGLOG("lock-resource returning %d\n", lwait.status);
-
-    return gulm_to_errno(lwait.status);
-}
-
-
-static int _unlock_resource(char *resource, int lockid)
-{
-    int status;
-    struct lock_wait lwait;
-
-    pthread_cond_init(&lwait.cond, NULL);
-    pthread_mutex_init(&lwait.mutex, NULL);
-    pthread_mutex_lock(&lwait.mutex);
-
-    dm_hash_insert(lock_hash, resource, &lwait);
-
-    DEBUGLOG("unlock_resource %s\n", resource);
-    status = lg_lock_state_req(gulm_if, resource, strlen(resource)+1,
-                              0, 0, 0,
-                              lg_lock_state_Unlock, 0, NULL, 0);
-
-    if (status)
-    {
-       DEBUGLOG("lg_lock_state(unlock) returned %d\n", status);
-       return status;
-    }
-
-    /* When we are shutting down, don't wait for unlocks
-       to be acknowledged, just do it. */
-    if (in_shutdown)
-           return status;
-
-    /* Wait for it to complete */
-
-    pthread_cond_wait(&lwait.cond, &lwait.mutex);
-    pthread_mutex_unlock(&lwait.mutex);
-
-    dm_hash_remove(lock_hash, resource);
-
-    return gulm_to_errno(lwait.status);
-}
-
-
-/* These two locking functions MUST be called in a seperate thread from
-   the clvmd main loop because they expect to be woken up by it.
-
-   These are abstractions around the real locking functions (above)
-   as we need to emulate the DLM's EX/PW/CW interaction with GULM using
-   two locks.
-   To aid unlocking, we store the lock mode in the lockid (as GULM
-   doesn't use this).
-*/
-static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
-{
-    int status;
-    char lock1[strlen(resource)+3];
-    char lock2[strlen(resource)+3];
-
-    snprintf(lock1, sizeof(lock1), "%s-1", resource);
-    snprintf(lock2, sizeof(lock2), "%s-2", resource);
-
-    switch (mode)
-    {
-    case LCK_EXCL:
-       status = _lock_resource(lock1, lg_lock_state_Exclusive, flags, lockid);
-       if (status)
-           goto out;
-
-       /* If we can't get this lock too then bail out */
-       status = _lock_resource(lock2, lg_lock_state_Exclusive, LCK_NONBLOCK, lockid);
-        if (status == lg_err_TryFailed)
-        {
-           _unlock_resource(lock1, *lockid);
-           status = -1;
-           errno = EAGAIN;
-        }
-       break;
-
-    case LCK_PREAD:
-    case LCK_READ:
-       status = _lock_resource(lock1, lg_lock_state_Shared, flags, lockid);
-       if (status)
-               goto out;
-       status = _unlock_resource(lock2, *lockid);
-       break;
-
-    case LCK_WRITE:
-       status = _lock_resource(lock2, lg_lock_state_Exclusive, flags, lockid);
-       if (status)
-               goto out;
-       status = _unlock_resource(lock1, *lockid);
-       break;
-
-    default:
-       status = -1;
-       errno = EINVAL;
-       break;
-    }
- out:
-    *lockid = mode;
-    return status;
-}
-
-static int _sync_unlock(const char *resource, int lockid)
-{
-    int status = 0;
-    char lock1[strlen(resource)+3];
-    char lock2[strlen(resource)+3];
-
-    snprintf(lock1, sizeof(lock1), "%s-1", resource);
-    snprintf(lock2, sizeof(lock2), "%s-2", resource);
-
-    /* The held lock mode is in the lock id */
-    assert(lockid == LCK_EXCL ||
-          lockid == LCK_READ ||
-          lockid == LCK_PREAD ||
-          lockid == LCK_WRITE);
-
-    status = _unlock_resource(lock1, lockid);
-    if (!status)
-           status = _unlock_resource(lock2, lockid);
-
-    return status;
-}
-
-static int _is_quorate()
-{
-       return gulm_quorate;
-}
-
-/* Get all the cluster node names & IPs from CCS and
-   add them to our node list so we know who to talk to.
-   Called when we start up and if we get sent SIGHUP.
-*/
-static int get_all_cluster_nodes()
-{
-    int ctree;
-    char *nodename;
-    int error;
-    int i;
-
-    /* Open the config file */
-    ctree = ccs_force_connect(NULL, 1);
-    if (ctree < 0)
-    {
-       log_error("Error connecting to CCS");
-       return -1;
-    }
-
-    for (i=1;;i++)
-    {
-       char nodekey[256];
-       char nodeip[GULM_MAX_CSID_LEN];
-       int  clvmflag = 1;
-       char *clvmflagstr;
-       char key[256];
-
-       sprintf(nodekey, "//cluster/clusternodes/clusternode[%d]/@name", i);
-       error = ccs_get(ctree, nodekey, &nodename);
-       if (error)
-           break;
-
-       sprintf(key, "//cluster/clusternodes/clusternode[@name=\"%s\"]/clvm", nodename);
-       if (!ccs_get(ctree, key, &clvmflagstr))
-       {
-           clvmflag = atoi(clvmflagstr);
-           free(clvmflagstr);
-       }
-
-       DEBUGLOG("Got node %s from ccs(clvmflag = %d)\n", nodename, clvmflag);
-       if ((get_ip_address(nodename, nodeip) == 0) && clvmflag)
-       {
-           struct node_info *ninfo;
-
-           /* If it's not in the list, then add it */
-           ninfo = dm_hash_lookup_binary(node_hash, nodeip, GULM_MAX_CSID_LEN);
-           if (!ninfo)
-           {
-               ninfo = malloc(sizeof(struct node_info));
-               if (!ninfo)
-               {
-                   syslog(LOG_ERR, "Cannot alloc memory for node info\n");
-                   ccs_disconnect(ctree);
-                   return -1;
-               }
-               strcpy(ninfo->name, nodename);
-
-               ninfo->state = NODE_DOWN;
-               dm_hash_insert_binary(node_hash, nodeip, GULM_MAX_CSID_LEN, ninfo);
-           }
-       }
-       else
-       {
-               if (!clvmflag) {
-                       DEBUGLOG("node %s has clvm disabled\n", nodename);
-               }
-               else {
-                       DEBUGLOG("Cannot resolve host name %s\n", nodename);
-                       log_error("Cannot resolve host name %s\n", nodename);
-               }
-       }
-       free(nodename);
-    }
-
-    /* Finished with config file */
-    ccs_disconnect(ctree);
-
-    return 0;
-}
-
-static int _get_main_cluster_fd(void)
-{
-       return get_main_gulm_cluster_fd();
-}
-
-static int _cluster_fd_callback(struct local_client *fd, char *buf, int len, const char *csid, struct local_client **new_client)
-{
-       return cluster_fd_gulm_callback(fd, buf, len, csid, new_client);
-}
-
-static int _cluster_send_message(const void *buf, int msglen, const char *csid, const char *errtext)
-{
-       return gulm_cluster_send_message((char *)buf, msglen, csid, errtext);
-}
-
-static int _get_cluster_name(char *buf, int buflen)
-{
-       strncpy(buf, cluster_name, buflen);
-       return 0;
-}
-
-static struct cluster_ops _cluster_gulm_ops = {
-       .cluster_init_completed   = NULL,
-       .cluster_send_message     = _cluster_send_message,
-       .name_from_csid           = gulm_name_from_csid,
-       .csid_from_name           = _csid_from_name,
-       .get_num_nodes            = _get_num_nodes,
-       .cluster_fd_callback      = _cluster_fd_callback,
-       .get_main_cluster_fd      = _get_main_cluster_fd,
-       .cluster_do_node_callback = _cluster_do_node_callback,
-       .is_quorate               = _is_quorate,
-       .get_our_csid             = _get_our_csid,
-       .add_up_node              = gulm_add_up_node,
-       .reread_config            = _reread_config,
-       .cluster_closedown        = _cluster_closedown,
-       .get_cluster_name         = _get_cluster_name,
-       .sync_lock                = _sync_lock,
-       .sync_unlock              = _sync_unlock,
-};
-
-struct cluster_ops *init_gulm_cluster(void)
-{
-       if (!_init_cluster())
-               return &_cluster_gulm_ops;
-       else
-               return NULL;
-}
diff --git a/daemons/clvmd/clvmd-gulm.h b/daemons/clvmd/clvmd-gulm.h
deleted file mode 100644 (file)
index 9416f5c..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-extern int get_next_node_csid(void **context, char *csid);
-extern void add_down_node(char *csid);
-extern int gulm_fd(void);
-extern int get_ip_address(const char *node, char *addr);
-extern void tcp_remove_client(const char *csid);
-extern int alloc_client(int fd, const char *csid, struct local_client **new_client);
-
-void gulm_add_up_node(const char *csid);
-int gulm_name_from_csid(const char *csid, char *name);
index fc98b50c8ca3862598dea1d7a2d45832c2cdd5f2..9ce73d6a77f333ecd155d520af733753aba929dc 100644 (file)
@@ -197,14 +197,13 @@ static int add_internal_client(int fd, fd_callback_t callback)
 
        DEBUGLOG("Add_internal_client, fd = %d\n", fd);
 
-       client = malloc(sizeof(struct local_client));
+       client = calloc(1, sizeof(struct local_client));
        if (!client)
        {
                DEBUGLOG("malloc failed\n");
                return -1;
        }
 
-       memset(client, 0, sizeof(struct local_client));
        client->fd = fd;
        client->type = CLUSTER_INTERNAL;
        client->callback = callback;
@@ -227,7 +226,7 @@ static void openais_cpg_deliver_callback (cpg_handle_t handle,
 
        memcpy(&target_nodeid, msg, OPENAIS_CSID_LEN);
 
-       DEBUGLOG("%u got message from nodeid %d for %d. len %d\n",
+       DEBUGLOG("%u got message from nodeid %d for %d. len %" PRIsize_t "\n",
                 our_nodeid, nodeid, target_nodeid, msg_len-4);
 
        if (nodeid != our_nodeid)
@@ -245,7 +244,8 @@ static void openais_cpg_confchg_callback(cpg_handle_t handle,
        int i;
        struct node_info *ninfo;
 
-       DEBUGLOG("confchg callback. %d joined, %d left, %d members\n",
+       DEBUGLOG("confchg callback. %" PRIsize_t " joined, "
+                "%" PRIsize_t " left, %" PRIsize_t " members\n",
                 joined_list_entries, left_list_entries, member_list_entries);
 
        for (i=0; i<joined_list_entries; i++) {
@@ -505,11 +505,11 @@ static int _lock_resource(char *resource, int mode, int flags, int *lockid)
                saLckResourceClose(res_handle);
                return ais_to_errno(err);
        }
-                       
+
        /* Wait for it to complete */
 
-       DEBUGLOG("lock_resource returning %d, lock_id=%llx\n", err,
-                lock_id);
+       DEBUGLOG("lock_resource returning %d, lock_id=%" PRIx64 "\n",
+                err, lock_id);
 
        linfo->lock_id = lock_id;
        linfo->res_handle = res_handle;
@@ -530,7 +530,7 @@ static int _unlock_resource(char *resource, int lockid)
        if (!linfo)
                return 0;
 
-       DEBUGLOG("unlock_resource: lockid: %llx\n", linfo->lock_id);
+       DEBUGLOG("unlock_resource: lockid: %" PRIx64 "\n", linfo->lock_id);
        err = saLckResourceUnlock(linfo->lock_id, SA_TIME_END);
        if (err != SA_AIS_OK)
        {
@@ -666,6 +666,7 @@ static int _get_cluster_name(char *buf, int buflen)
 }
 
 static struct cluster_ops _cluster_openais_ops = {
+       .name                     = "openais",
        .cluster_init_completed   = NULL,
        .cluster_send_message     = _cluster_send_message,
        .name_from_csid           = _name_from_csid,
index 335cb98f53fdd8b54360ee6b54fe15293ee2702a..3b35bf59fca197356f26d2e28d6ce0069c064ced 100644 (file)
 static const char SINGLENODE_CLVMD_SOCKNAME[] = DEFAULT_RUN_DIR "/clvmd_singlenode.sock";
 static int listen_fd = -1;
 
+static struct dm_hash_table *_locks;
+static int _lockid;
+
+struct lock {
+       int lockid;
+       int mode;
+       int excl;
+};
+
 static void close_comms(void)
 {
        if (listen_fd != -1 && close(listen_fd))
@@ -39,8 +48,15 @@ static void close_comms(void)
 
 static int init_comms(void)
 {
-       struct sockaddr_un addr;
        mode_t old_mask;
+       struct sockaddr_un addr = { .sun_family = AF_UNIX };
+
+       if (!dm_strncpy(addr.sun_path, SINGLENODE_CLVMD_SOCKNAME,
+                       sizeof(addr.sun_path))) {
+               DEBUGLOG("%s: singlenode socket name too long.",
+                        SINGLENODE_CLVMD_SOCKNAME);
+               return -1;
+       }
 
        close_comms();
 
@@ -53,12 +69,10 @@ static int init_comms(void)
                goto error;
        }
        /* Set Close-on-exec */
-       fcntl(listen_fd, F_SETFD, 1);
-
-       memset(&addr, 0, sizeof(addr));
-       memcpy(addr.sun_path, SINGLENODE_CLVMD_SOCKNAME,
-              sizeof(SINGLENODE_CLVMD_SOCKNAME));
-       addr.sun_family = AF_UNIX;
+       if (fcntl(listen_fd, F_SETFD, 1)) {
+               DEBUGLOG("Setting CLOEXEC on client fd failed: %s\n", strerror(errno));
+               goto error;
+       }
 
        if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
                DEBUGLOG("Can't bind local socket: %s\n", strerror(errno));
@@ -83,9 +97,16 @@ static int _init_cluster(void)
 {
        int r;
 
+       if (!(_locks = dm_hash_create(128))) {
+               DEBUGLOG("Failed to allocate single-node hash table.\n");
+               return 1;
+       }
+
        r = init_comms();
-       if (r)
+       if (r) {
+               dm_hash_destroy(_locks);
                return r;
+       }
 
        DEBUGLOG("Single-node cluster initialised.\n");
        return 0;
@@ -97,6 +118,9 @@ static void _cluster_closedown(void)
 
        DEBUGLOG("cluster_closedown\n");
        destroy_lvhash();
+       dm_hash_destroy(_locks);
+       _locks = NULL;
+       _lockid = 0;
 }
 
 static void _get_our_csid(char *csid)
@@ -136,95 +160,101 @@ static int _cluster_do_node_callback(struct local_client *master_client,
 
 int _lock_file(const char *file, uint32_t flags);
 
-static int *_locks = NULL;
-static char **_resources = NULL;
-static int _lock_max = 1;
 static pthread_mutex_t _lock_mutex = PTHREAD_MUTEX_INITIALIZER;
+/* Using one common condition for all locks for simplicity */
+static pthread_cond_t _lock_cond = PTHREAD_COND_INITIALIZER;
 
 /* Real locking */
 static int _lock_resource(const char *resource, int mode, int flags, int *lockid)
 {
-       int *_locks_1;
-       char **_resources_1;
-       int i, j;
+       struct lock *lck;
 
-       DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n",
+       DEBUGLOG("Locking resource %s, flags=%d, mode=%d\n",
                 resource, flags, mode);
 
- retry:
+       mode &= LCK_TYPE_MASK;
        pthread_mutex_lock(&_lock_mutex);
-
-       /* look for an existing lock for this resource */
-       for (i = 1; i < _lock_max; ++i) {
-               if (!_resources[i])
-                       break;
-               if (!strcmp(_resources[i], resource)) {
-                       if ((_locks[i] & LCK_TYPE_MASK) == LCK_WRITE ||
-                           (_locks[i] & LCK_TYPE_MASK) == LCK_EXCL) {
-                               DEBUGLOG("%s already write/exclusively locked...\n", resource);
-                               goto maybe_retry;
-                       }
-                       if ((mode & LCK_TYPE_MASK) == LCK_WRITE ||
-                           (mode & LCK_TYPE_MASK) == LCK_EXCL) {
-                               DEBUGLOG("%s already locked and WRITE/EXCL lock requested...\n",
-                                        resource);
-                               goto maybe_retry;
-                       }
-               }
+retry:
+       if (!(lck = dm_hash_lookup(_locks, resource))) {
+               /* Add new locked resource */
+               if (!(lck = dm_zalloc(sizeof(struct lock))) ||
+                   !dm_hash_insert(_locks, resource, lck))
+                       goto bad;
+
+               lck->lockid = ++_lockid;
+               goto out;
        }
 
-       if (i == _lock_max) { /* out of lock slots, extend */
-               _locks_1 = dm_realloc(_locks, 2 * _lock_max * sizeof(int));
-               if (!_locks_1)
-                       return 1; /* fail */
-               _locks = _locks_1;
-               _resources_1 = dm_realloc(_resources, 2 * _lock_max * sizeof(char *));
-               if (!_resources_1) {
-                       /* _locks may get realloc'd twice, but that should be safe */
-                       return 1; /* fail */
-               }
-               _resources = _resources_1;
-               /* clear the new resource entries */
-               for (j = _lock_max; j < 2 * _lock_max; ++j)
-                       _resources[j] = NULL;
-               _lock_max = 2 * _lock_max;
+        /* Update/convert lock */
+       if (flags == LCKF_CONVERT) {
+               if (lck->excl)
+                       mode = LCK_EXCL;
+       } else if ((lck->mode == LCK_WRITE) || (lck->mode == LCK_EXCL)) {
+               DEBUGLOG("Resource %s already %s locked (%d)...\n", resource,
+                        (lck->mode == LCK_WRITE) ? "write" : "exclusively", lck->lockid);
+               goto maybe_retry;
+       } else if (lck->mode > mode) {
+               DEBUGLOG("Resource %s already locked and %s lock requested...\n",
+                        resource,
+                        (mode == LCK_READ) ? "READ" :
+                        (mode == LCK_WRITE) ? "WRITE" : "EXCLUSIVE");
+               goto maybe_retry;
        }
 
-       /* resource is not currently locked, grab it */
-
-       *lockid = i;
-       _locks[i] = mode;
-       _resources[i] = dm_strdup(resource);
-
-       DEBUGLOG("%s locked -> %d\n", resource, i);
-
+out:
+       *lockid = lck->lockid;
+       lck->mode = mode;
+       lck->excl |= (mode == LCK_EXCL);
+       DEBUGLOG("Locked resource %s, lockid=%d, mode=%d\n", resource, lck->lockid, mode);
+       pthread_cond_broadcast(&_lock_cond); /* wakeup waiters */
        pthread_mutex_unlock(&_lock_mutex);
+
        return 0;
- maybe_retry:
-       pthread_mutex_unlock(&_lock_mutex);
+
+maybe_retry:
        if (!(flags & LCK_NONBLOCK)) {
-               usleep(10000);
+               pthread_cond_wait(&_lock_cond, &_lock_mutex);
+               DEBUGLOG("Resource %s RETRYING lock...\n", resource);
                goto retry;
        }
+bad:
+       DEBUGLOG("Failed to lock resource %s\n", resource);
+       pthread_mutex_unlock(&_lock_mutex);
 
        return 1; /* fail */
 }
 
 static int _unlock_resource(const char *resource, int lockid)
 {
-       DEBUGLOG("unlock_resource: %s lockid: %x\n", resource, lockid);
-       if(!_resources[lockid]) {
-               DEBUGLOG("(%s) %d not locked\n", resource, lockid);
+       struct lock *lck;
+
+       if (lockid < 0) {
+               DEBUGLOG("Not tracking unlock of lockid -1: %s, lockid=%d\n",
+                        resource, lockid);
+               return 0;
+       }
+
+       DEBUGLOG("Unlocking resource %s, lockid=%d\n", resource, lockid);
+       pthread_mutex_lock(&_lock_mutex);
+
+       if (!(lck = dm_hash_lookup(_locks, resource))) {
+               pthread_mutex_unlock(&_lock_mutex);
+               DEBUGLOG("Resource %s, lockid=%d is not locked.\n", resource, lockid);
                return 1;
        }
-       if(strcmp(_resources[lockid], resource)) {
-               DEBUGLOG("%d has wrong resource (requested %s, got %s)\n",
-                        lockid, resource, _resources[lockid]);
+
+       if (lck->lockid != lockid) {
+               pthread_mutex_unlock(&_lock_mutex);
+               DEBUGLOG("Resource %s has wrong lockid %d, expected %d.\n",
+                        resource, lck->lockid, lockid);
                return 1;
        }
 
-       dm_free(_resources[lockid]);
-       _resources[lockid] = 0;
+       dm_hash_remove(_locks, resource);
+       dm_free(lck);
+       pthread_cond_broadcast(&_lock_cond); /* wakeup waiters */
+       pthread_mutex_unlock(&_lock_mutex);
+
        return 0;
 }
 
@@ -260,6 +290,7 @@ static int _get_cluster_name(char *buf, int buflen)
 }
 
 static struct cluster_ops _cluster_singlenode_ops = {
+       .name                     = "singlenode",
        .cluster_init_completed   = NULL,
        .cluster_send_message     = _cluster_send_message,
        .name_from_csid           = _name_from_csid,
index 1a35c495b6a161658320f3621990885ee6d5f6c6..ac465d97becce34c6e0870fe1a7b579b5cd6a42b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -20,6 +20,7 @@
 #include "clvmd-common.h"
 
 #include <pthread.h>
+#include <getopt.h>
 
 #include "clvmd-comms.h"
 #include "clvm.h"
@@ -48,6 +49,7 @@
 #endif
 
 #define MAX_RETRIES 4
+#define MAX_MISSING_LEN 8000 /* Max supported clvmd message size ? */
 
 #define ISLOCAL_CSID(c) (memcmp(c, our_csid, max_csid_len) == 0)
 
@@ -77,15 +79,18 @@ struct lvm_thread_cmd {
 };
 
 struct lvm_startup_params {
-       int using_gulm;
-       char **argv;
+       struct dm_hash_table *excl_uuid;
 };
 
-debug_t debug;
+static debug_t debug = DEBUG_OFF;
+static int foreground_mode = 0;
 static pthread_t lvm_thread;
+/* Stack size 128KiB for thread, must be bigger then DEFAULT_RESERVED_STACK */
+static const size_t STACK_SIZE = 128 * 1024;
+static pthread_attr_t stack_attr;
 static pthread_mutex_t lvm_thread_mutex;
 static pthread_cond_t lvm_thread_cond;
-static pthread_mutex_t lvm_start_mutex;
+static pthread_barrier_t lvm_start_barrier;
 static struct dm_list lvm_cmd_head;
 static volatile sig_atomic_t quit = 0;
 static volatile sig_atomic_t reread_config = 0;
@@ -99,9 +104,7 @@ static int child_pipe[2];
 #define DFAIL_TIMEOUT    5
 #define SUCCESS          0
 
-typedef enum {IF_AUTO, IF_CMAN, IF_GULM, IF_OPENAIS, IF_COROSYNC, IF_SINGLENODE} if_type_t;
-
-typedef void *(lvm_pthread_fn_t)(void*);
+typedef enum {IF_AUTO, IF_CMAN, IF_OPENAIS, IF_COROSYNC, IF_SINGLENODE} if_type_t;
 
 /* Prototypes for code further down */
 static void sigusr2_handler(int sig);
@@ -132,7 +135,7 @@ static int check_all_clvmds_running(struct local_client *client);
 static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
                                     int len, const char *csid,
                                     struct local_client **new_client);
-static void lvm_thread_fn(void *) __attribute__ ((noreturn));
+static void *lvm_thread_fn(void *) __attribute__((noreturn));
 static int add_to_lvmqueue(struct local_client *client, struct clvm_header *msg,
                           int msglen, const char *csid);
 static int distribute_command(struct local_client *thisfd);
@@ -145,12 +148,12 @@ static if_type_t get_cluster_type(void);
 
 static void usage(const char *prog, FILE *file)
 {
-       fprintf(file, "Usage:\n"
-               "%s [Vhd]\n\n"
+       fprintf(file, "Usage: %s [options]\n"
                "   -V       Show version of clvmd\n"
                "   -h       Show this help information\n"
-               "   -d       Set debug level\n"
-               "            If starting clvmd then don't fork, run in the foreground\n"
+               "   -d[n]    Set debug logging (0:none, 1:stderr (implies -f option), 2:syslog)\n"
+               "   -f       Don't fork, run in the foreground\n"
+               "   -E<lockuuid> Take this lock uuid as exclusively locked resource (for restart)\n"
                "   -R       Tell all running clvmds in the cluster to reload their device cache\n"
                "   -S       Restart clvmd, preserving exclusive locks\n"
                "   -C       Sets debug level (from -d) on all clvmd instances clusterwide\n"
@@ -167,9 +170,6 @@ static void usage(const char *prog, FILE *file)
 #ifdef USE_OPENAIS
                "openais "
 #endif
-#ifdef USE_GULM
-               "gulm "
-#endif
 #ifdef USE_SINGLENODE
                "singlenode "
 #endif
@@ -199,7 +199,8 @@ static void safe_close(int *fd)
        if (*fd >= 0) {
                int to_close = *fd;
                *fd = -1;
-               close(to_close);
+               if (close(to_close))
+                       log_sys_error("close", ""); /* path */
        }
 }
 
@@ -209,14 +210,15 @@ void debuglog(const char *fmt, ...)
        va_list ap;
        static int syslog_init = 0;
 
-       if (debug == DEBUG_STDERR) {
+       switch (clvmd_get_debug()) {
+       case DEBUG_STDERR:
                va_start(ap,fmt);
                time(&P);
                fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime(&P)+4 );
                vfprintf(stderr, fmt, ap);
                va_end(ap);
-       }
-       if (debug == DEBUG_SYSLOG) {
+               break;
+       case DEBUG_SYSLOG:
                if (!syslog_init) {
                        openlog("clvmd", LOG_PID, LOG_DAEMON);
                        syslog_init = 1;
@@ -225,9 +227,28 @@ void debuglog(const char *fmt, ...)
                va_start(ap,fmt);
                vsyslog(LOG_DEBUG, fmt, ap);
                va_end(ap);
+               break;
+       case DEBUG_OFF:
+               break;
        }
 }
 
+void clvmd_set_debug(debug_t new_debug)
+{
+       if (!foreground_mode && new_debug == DEBUG_STDERR)
+               new_debug = DEBUG_SYSLOG;
+
+       if (new_debug > DEBUG_SYSLOG)
+               new_debug = DEBUG_SYSLOG;
+
+       debug = new_debug;
+}
+
+debug_t clvmd_get_debug(void)
+{
+       return debug;
+}
+
 static const char *decode_cmd(unsigned char cmdl)
 {
        static char buf[128];
@@ -276,12 +297,15 @@ static const char *decode_cmd(unsigned char cmdl)
        case CLVMD_CMD_RESTART:
                command = "RESTART";
                break;
+       case CLVMD_CMD_SYNC_NAMES:
+               command = "SYNC_NAMES";
+               break;
        default:
                command = "unknown";
                break;
        }
 
-       sprintf(buf, "%s (0x%x)", command, cmdl);
+       snprintf(buf, sizeof(buf), "%s (0x%x)", command, cmdl);
 
        return buf;
 }
@@ -312,52 +336,63 @@ static void check_permissions(void)
 int main(int argc, char *argv[])
 {
        int local_sock;
-       struct local_client *newfd;
-       struct utsname nodeinfo;
+       struct local_client *newfd, *delfd;
        struct lvm_startup_params lvm_params;
-       signed char opt;
+       int opt;
        int cmd_timeout = DEFAULT_CMD_TIMEOUT;
        int start_timeout = 0;
        if_type_t cluster_iface = IF_AUTO;
        sigset_t ss;
-       int using_gulm = 0;
-       int debug_opt = 0;
+       debug_t debug_opt = DEBUG_OFF;
+       debug_t debug_arg = DEBUG_OFF;
        int clusterwide_opt = 0;
        mode_t old_mask;
+       int ret = 1;
+
+       struct option longopts[] = {
+               { "help", 0, 0, 'h' },
+               { NULL, 0, 0, 0 }
+       };
+
+       if (!(lvm_params.excl_uuid = dm_hash_create(128))) {
+               fprintf(stderr, "Failed to allocate hash table\n");
+               return 1;
+       }
 
        /* Deal with command-line arguments */
        opterr = 0;
        optind = 0;
-       while ((opt = getopt(argc, argv, "?vVhd::t:RST:CI:E:")) != EOF) {
+       while ((opt = getopt_long(argc, argv, "vVhfd::t:RST:CI:E:",
+                                 longopts, NULL)) != -1) {
                switch (opt) {
                case 'h':
                        usage(argv[0], stdout);
                        exit(0);
 
-               case '?':
-                       usage(argv[0], stderr);
-                       exit(0);
-
                case 'R':
                        check_permissions();
-                       return refresh_clvmd(1)==1?0:1;
+                       ret = (refresh_clvmd(1) == 1) ? 0 : 1;
+                       goto out;
 
                case 'S':
                        check_permissions();
-                       return restart_clvmd(clusterwide_opt)==1?0:1;
+                       ret = (restart_clvmd(clusterwide_opt) == 1) ? 0 : 1;
+                       goto out;
 
                case 'C':
                        clusterwide_opt = 1;
                        break;
 
                case 'd':
-                       debug_opt = 1;
-                       if (optarg)
-                               debug = atoi(optarg);
-                       else
-                               debug = DEBUG_STDERR;
+                       debug_opt = DEBUG_STDERR;
+                       debug_arg = optarg ? (debug_t) atoi(optarg) : DEBUG_STDERR;
+                       if (debug_arg == DEBUG_STDERR)
+                               foreground_mode = 1;
                        break;
 
+               case 'f':
+                       foreground_mode = 1;
+                       break;
                case 't':
                        cmd_timeout = atoi(optarg);
                        if (!cmd_timeout) {
@@ -369,6 +404,12 @@ int main(int argc, char *argv[])
                case 'I':
                        cluster_iface = parse_cluster_interface(optarg);
                        break;
+               case 'E':
+                       if (!dm_hash_insert(lvm_params.excl_uuid, optarg, optarg)) {
+                               fprintf(stderr, "Failed to allocate hash entry\n");
+                               goto out;
+                       }
+                       break;
                case 'T':
                        start_timeout = atoi(optarg);
                        if (start_timeout <= 0) {
@@ -386,20 +427,14 @@ int main(int argc, char *argv[])
                        exit(0);
                        break;
 
+               default:
+                       usage(argv[0], stderr);
+                       exit(2);
                }
        }
 
        check_permissions();
 
-       /* Setting debug options on an existing clvmd */
-       if (debug_opt && !check_local_clvmd()) {
-
-               /* Sending to stderr makes no sense for a detached daemon */
-               if (debug == DEBUG_STDERR)
-                       debug = DEBUG_SYSLOG;
-               return debug_clvmd(debug, clusterwide_opt)==1?0:1;
-       }
-
        /*
         * Switch to C locale to avoid reading large locale-archive file
         * used by some glibc (on some distributions it takes over 100MB).
@@ -408,12 +443,19 @@ int main(int argc, char *argv[])
        if (setenv("LANG", "C", 1))
                perror("Cannot set LANG to C");
 
+       /* Setting debug options on an existing clvmd */
+       if (debug_opt && !check_local_clvmd()) {
+               dm_hash_destroy(lvm_params.excl_uuid);
+               return debug_clvmd(debug_arg, clusterwide_opt)==1?0:1;
+       }
+
+       clvmd_set_debug(debug_opt);
+
        /* Fork into the background (unless requested not to) */
-       if (debug != DEBUG_STDERR) {
+       if (!foreground_mode)
                be_daemon(start_timeout);
-       }
 
-        dm_prepare_selinux_context(DEFAULT_RUN_DIR, S_IFDIR);
+        (void) dm_prepare_selinux_context(DEFAULT_RUN_DIR, S_IFDIR);
         old_mask = umask(0077);
         if (dm_create_dir(DEFAULT_RUN_DIR) == 0) {
                 DEBUGLOG("clvmd: unable to create %s directory\n",
@@ -447,7 +489,7 @@ int main(int argc, char *argv[])
 
        /* Set up signal handlers, USR1 is for cluster change notifications (in cman)
           USR2 causes child threads to exit.
-          HUP causes gulm version to re-read nodes list from CCS.
+          (HUP used to cause gulm to re-read the nodes list from CCS.)
           PIPE should be ignored */
        signal(SIGUSR2, sigusr2_handler);
        signal(SIGHUP,  sighup_handler);
@@ -462,9 +504,14 @@ int main(int argc, char *argv[])
 
        /* Initialise the LVM thread variables */
        dm_list_init(&lvm_cmd_head);
+       if (pthread_attr_init(&stack_attr) ||
+           pthread_attr_setstacksize(&stack_attr, STACK_SIZE)) {
+               log_sys_error("pthread_attr_init", "");
+               exit(1);
+       }
        pthread_mutex_init(&lvm_thread_mutex, NULL);
        pthread_cond_init(&lvm_thread_cond, NULL);
-       pthread_mutex_init(&lvm_start_mutex, NULL);
+       pthread_barrier_init(&lvm_start_barrier, NULL, 2);
        init_lvhash();
 
        /* Start the cluster interface */
@@ -479,16 +526,6 @@ int main(int argc, char *argv[])
                syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to CMAN");
        }
 #endif
-#ifdef USE_GULM
-       if (!clops)
-               if ((cluster_iface == IF_AUTO || cluster_iface == IF_GULM) && (clops = init_gulm_cluster())) {
-                       max_csid_len = GULM_MAX_CSID_LEN;
-                       max_cluster_message = GULM_MAX_CLUSTER_MESSAGE;
-                       max_cluster_member_name_len = GULM_MAX_CLUSTER_MEMBER_NAME_LEN;
-                       using_gulm = 1;
-                       syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to GULM");
-               }
-#endif
 #ifdef USE_COROSYNC
        if (!clops)
                if (((cluster_iface == IF_AUTO || cluster_iface == IF_COROSYNC) && (clops = init_corosync_cluster()))) {
@@ -526,7 +563,6 @@ int main(int argc, char *argv[])
        DEBUGLOG("Cluster ready, doing some more initialisation\n");
 
        /* Save our CSID */
-       uname(&nodeinfo);
        clops->get_our_csid(our_csid);
 
        /* Initialise the FD list head */
@@ -553,16 +589,12 @@ int main(int argc, char *argv[])
        DEBUGLOG("starting LVM thread\n");
 
        /* Don't let anyone else to do work until we are started */
-       pthread_mutex_lock(&lvm_start_mutex);
-       lvm_params.using_gulm = using_gulm;
-       lvm_params.argv = argv;
-       pthread_create(&lvm_thread, NULL, (lvm_pthread_fn_t*)lvm_thread_fn,
-                       (void *)&lvm_params);
+       pthread_create(&lvm_thread, &stack_attr, lvm_thread_fn, &lvm_params);
+
+       /* Don't start until the LVM thread is ready */
+       pthread_barrier_wait(&lvm_start_barrier);
 
        /* Tell the rest of the cluster our version number */
-       /* CMAN can do this immediately, gulm needs to wait until
-          the core initialisation has finished and the node list
-          has been gathered */
        if (clops->cluster_init_completed)
                clops->cluster_init_completed();
 
@@ -576,15 +608,39 @@ int main(int argc, char *argv[])
        /* Do some work */
        main_loop(local_sock, cmd_timeout);
 
+       pthread_mutex_lock(&lvm_thread_mutex);
+       pthread_cond_signal(&lvm_thread_cond);
+       pthread_mutex_unlock(&lvm_thread_mutex);
+       if ((errno = pthread_join(lvm_thread, NULL)))
+               log_sys_error("pthread_join", "");
+
        close_local_sock(local_sock);
        destroy_lvm();
 
-       return 0;
+       for (newfd = local_client_head.next; newfd != NULL;) {
+               delfd = newfd;
+               newfd = newfd->next;
+               if (delfd->fd == local_sock)
+                       delfd->fd = -1;
+               /*
+                * FIXME:
+                * needs cleanup code from read_from_local_sock() for now
+                * break of 'clvmd' may access already free memory here.
+                */
+               safe_close(&(delfd->fd));
+               free(delfd);
+       }
+
+       ret = 0;
+out:
+       dm_hash_destroy(lvm_params.excl_uuid);
+
+       return ret;
 }
 
-/* Called when the GuLM cluster layer has completed initialisation.
+/* Called when the cluster layer has completed initialisation.
    We send the version message */
-void clvmd_cluster_init_completed()
+void clvmd_cluster_init_completed(void)
 {
        send_version_message();
 }
@@ -616,7 +672,8 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
        if (client_fd >= 0) {
                newfd = malloc(sizeof(struct local_client));
                if (!newfd) {
-                       close(client_fd);
+                       if (close(client_fd))
+                                log_sys_error("close", "socket");
                        return 1;
                }
 
@@ -666,9 +723,9 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
 
        /* EOF on pipe or an error, close it */
        if (len <= 0) {
-               int jstat;
                void *ret = &status;
-               close(thisfd->fd);
+               if (close(thisfd->fd))
+                       log_sys_error("close", "local_pipe");
 
                /* Clear out the cross-link */
                if (thisfd->bits.pipe.client != NULL)
@@ -677,7 +734,10 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
 
                /* Reap child thread */
                if (thisfd->bits.pipe.threadid) {
-                       jstat = pthread_join(thisfd->bits.pipe.threadid, &ret);
+                       if ((errno = pthread_join(thisfd->bits.pipe.threadid,
+                                                 &ret)))
+                               log_sys_error("pthread_join", "");
+
                        thisfd->bits.pipe.threadid = 0;
                        if (thisfd->bits.pipe.client != NULL)
                                thisfd->bits.pipe.client->bits.localsock.
@@ -689,27 +749,25 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
                         status, sock_client);
                /* But has the client gone away ?? */
                if (sock_client == NULL) {
-                       DEBUGLOG
-                           ("Got PIPE response for dead client, ignoring it\n");
+                       DEBUGLOG("Got PIPE response for dead client, ignoring it\n");
                } else {
                        /* If error then just return that code */
                        if (status)
                                send_local_reply(sock_client, status,
                                                 sock_client->fd);
                        else {
-                               if (sock_client->bits.localsock.state ==
-                                   POST_COMMAND) {
+                               /* FIXME: closer inspect this code since state is write thread protected */
+                               pthread_mutex_lock(&sock_client->bits.localsock.mutex);
+                               if (sock_client->bits.localsock.state == POST_COMMAND) {
+                                       pthread_mutex_unlock(&sock_client->bits.localsock.mutex);
                                        send_local_reply(sock_client, 0,
                                                         sock_client->fd);
-                               } else  // PRE_COMMAND finished.
-                               {
-                                       if (
-                                           (status =
-                                            distribute_command(sock_client)) !=
-                                           0) send_local_reply(sock_client,
-                                                               EFBIG,
-                                                               sock_client->
-                                                               fd);
+                               } else {
+                                       /* PRE_COMMAND finished. */
+                                       pthread_mutex_unlock(&sock_client->bits.localsock.mutex);
+                                       if ((status = distribute_command(sock_client)))
+                                               send_local_reply(sock_client, EFBIG,
+                                                                sock_client->fd);
                                }
                        }
                }
@@ -774,9 +832,10 @@ static void request_timed_out(struct local_client *client)
 /* This is where the real work happens */
 static void main_loop(int local_sock, int cmd_timeout)
 {
+       sigset_t ss;
+
        DEBUGLOG("Using timeout of %d seconds\n", cmd_timeout);
 
-       sigset_t ss;
        sigemptyset(&ss);
        sigaddset(&ss, SIGINT);
        sigaddset(&ss, SIGTERM);
@@ -827,7 +886,6 @@ static void main_loop(int local_sock, int cmd_timeout)
                                        struct local_client *free_fd;
                                        lastfd->next = thisfd->next;
                                        free_fd = thisfd;
-                                       thisfd = lastfd;
 
                                        DEBUGLOG("removeme set for fd %d\n", free_fd->fd);
 
@@ -863,7 +921,6 @@ static void main_loop(int local_sock, int cmd_timeout)
                                                         ret, errno);
                                                lastfd->next = thisfd->next;
                                                free_fd = thisfd;
-                                               thisfd = lastfd;
                                                safe_close(&(free_fd->fd));
 
                                                /* Queue cleanup, this also frees the client struct */
@@ -987,7 +1044,10 @@ static void be_daemon(int timeout)
                exit(3);
        }
 
-       pipe(child_pipe);
+       if (pipe(child_pipe)) {
+               perror("Error creating pipe");
+               exit(3);
+       }
 
        switch (fork()) {
        case -1:
@@ -995,11 +1055,11 @@ static void be_daemon(int timeout)
                exit(2);
 
        case 0:         /* Child */
-               close(child_pipe[0]);
+               (void) close(child_pipe[0]);
                break;
 
        default:       /* Parent */
-               close(child_pipe[1]);
+               (void) close(child_pipe[1]);
                wait_for_child(child_pipe[0], timeout);
        }
 
@@ -1030,9 +1090,9 @@ static int read_from_local_sock(struct local_client *thisfd)
        int len;
        int argslen;
        int missing_len;
-       char buffer[PIPE_BUF];
+       char buffer[PIPE_BUF + 1];
 
-       len = read(thisfd->fd, buffer, sizeof(buffer));
+       len = read(thisfd->fd, buffer, sizeof(buffer) - 1);
        if (len == -1 && errno == EINTR)
                return 1;
 
@@ -1041,7 +1101,6 @@ static int read_from_local_sock(struct local_client *thisfd)
        /* EOF or error on socket */
        if (len <= 0) {
                int *status;
-               int jstat;
 
                DEBUGLOG("EOF on local socket: inprogress=%d\n",
                         thisfd->bits.localsock.in_progress);
@@ -1068,9 +1127,10 @@ static int read_from_local_sock(struct local_client *thisfd)
                        pthread_cond_signal(&thisfd->bits.localsock.cond);
                        pthread_mutex_unlock(&thisfd->bits.localsock.mutex);
 
-                       jstat =
-                           pthread_join(thisfd->bits.localsock.threadid,
-                                        (void **) &status);
+                       if ((errno = pthread_join(thisfd->bits.localsock.threadid,
+                                                 (void **) &status)))
+                               log_sys_error("pthread_join", "");
+
                        DEBUGLOG("Joined child thread\n");
 
                        thisfd->bits.localsock.threadid = 0;
@@ -1083,8 +1143,8 @@ static int read_from_local_sock(struct local_client *thisfd)
                                struct local_client *lastfd = NULL;
                                struct local_client *free_fd = NULL;
 
-                               close(thisfd->bits.localsock.pipe_client->fd);  /* Close pipe */
-                               close(thisfd->bits.localsock.pipe);
+                               (void) close(thisfd->bits.localsock.pipe_client->fd);   /* Close pipe */
+                               (void) close(thisfd->bits.localsock.pipe);
 
                                /* Remove pipe client */
                                for (newfd = &local_client_head; newfd != NULL;
@@ -1122,6 +1182,7 @@ static int read_from_local_sock(struct local_client *thisfd)
                struct clvm_header *inheader;
                int status;
 
+               buffer[len] = 0; /* Ensure \0 terminated */
                inheader = (struct clvm_header *) buffer;
 
                /* Fill in the client ID */
@@ -1129,20 +1190,16 @@ static int read_from_local_sock(struct local_client *thisfd)
 
                /* If we are already busy then return an error */
                if (thisfd->bits.localsock.in_progress) {
-                       struct clvm_header reply;
-                       reply.cmd = CLVMD_CMD_REPLY;
-                       reply.status = EBUSY;
-                       reply.arglen = 0;
-                       reply.flags = 0;
+                       struct clvm_header reply = {
+                               .cmd = CLVMD_CMD_REPLY,
+                               .status = EBUSY
+                       };
                        send_message(&reply, sizeof(reply), our_csid,
                                     thisfd->fd,
                                     "Error sending EBUSY reply to local user");
                        return len;
                }
 
-               /* Free any old buffer space */
-               free(thisfd->bits.localsock.cmd);
-
                /* See if we have the whole message */
                argslen =
                    len - strlen(inheader->node) - sizeof(struct clvm_header);
@@ -1151,15 +1208,30 @@ static int read_from_local_sock(struct local_client *thisfd)
                if (missing_len < 0)
                        missing_len = 0;
 
+               /* We need at least sizeof(struct clvm_header) bytes in buffer */
+               if (len < sizeof(struct clvm_header) || argslen < 0 ||
+                   missing_len > MAX_MISSING_LEN) {
+                       struct clvm_header reply = {
+                               .cmd = CLVMD_CMD_REPLY,
+                               .status = EINVAL
+                       };
+                       send_message(&reply, sizeof(reply), our_csid,
+                                    thisfd->fd,
+                                    "Error sending EINVAL reply to local user");
+                       return 0;
+               }
+
+               /* Free any old buffer space */
+               free(thisfd->bits.localsock.cmd);
+
                /* Save the message */
                thisfd->bits.localsock.cmd = malloc(len + missing_len);
 
                if (!thisfd->bits.localsock.cmd) {
-                       struct clvm_header reply;
-                       reply.cmd = CLVMD_CMD_REPLY;
-                       reply.status = ENOMEM;
-                       reply.arglen = 0;
-                       reply.flags = 0;
+                       struct clvm_header reply = {
+                               .cmd = CLVMD_CMD_REPLY,
+                               .status = ENOMEM
+                       };
                        send_message(&reply, sizeof(reply), our_csid,
                                     thisfd->fd,
                                     "Error sending ENOMEM reply to local user");
@@ -1174,15 +1246,22 @@ static int read_from_local_sock(struct local_client *thisfd)
                        char *argptr =
                            inheader->node + strlen(inheader->node) + 1;
 
-                       while (missing_len > 0 && len >= 0) {
-                               DEBUGLOG
-                                   ("got %d bytes, need another %d (total %d)\n",
-                                    argslen, missing_len, inheader->arglen);
+                       while (missing_len > 0) {
+                               DEBUGLOG("got %d bytes, need another %d (total %d)\n",
+                                        argslen, missing_len, inheader->arglen);
                                len = read(thisfd->fd, argptr + argslen,
                                           missing_len);
-                               if (len >= 0) {
+                               if (len == -1 && errno == EINTR)
+                                       continue;
+                               if (len > 0) {
                                        missing_len -= len;
                                        argslen += len;
+                               } else {
+                                       /* EOF or error on socket */
+                                       DEBUGLOG("EOF on local socket\n");
+                                       free(thisfd->bits.localsock.cmd);
+                                       thisfd->bits.localsock.cmd = NULL;
+                                       return 0;
                                }
                        }
                }
@@ -1207,13 +1286,12 @@ static int read_from_local_sock(struct local_client *thisfd)
                /* Check the node name for validity */
                if (inheader->node[0] && clops->csid_from_name(csid, inheader->node)) {
                        /* Error, node is not in the cluster */
-                       struct clvm_header reply;
-                       DEBUGLOG("Unknown node: '%s'\n", inheader->node);
+                       struct clvm_header reply = {
+                               .cmd = CLVMD_CMD_REPLY,
+                               .status = ENOENT
+                       };
 
-                       reply.cmd = CLVMD_CMD_REPLY;
-                       reply.status = ENOENT;
-                       reply.flags = 0;
-                       reply.arglen = 0;
+                       DEBUGLOG("Unknown node: '%s'\n", inheader->node);
                        send_message(&reply, sizeof(reply), our_csid,
                                     thisfd->fd,
                                     "Error sending ENOENT reply to local user");
@@ -1234,17 +1312,29 @@ static int read_from_local_sock(struct local_client *thisfd)
                }
 
                /* Create a pipe and add the reading end to our FD list */
-               pipe(comms_pipe);
+               if (pipe(comms_pipe)) {
+                       struct clvm_header reply = {
+                               .cmd = CLVMD_CMD_REPLY,
+                               .status = EBUSY
+                       };
+
+                       DEBUGLOG("creating pipe failed: %s\n", strerror(errno));
+                       send_message(&reply, sizeof(reply), our_csid,
+                                    thisfd->fd,
+                                    "Error sending EBUSY reply to local user");
+                       return len;
+               }
+
                newfd = malloc(sizeof(struct local_client));
                if (!newfd) {
-                       struct clvm_header reply;
-                       close(comms_pipe[0]);
-                       close(comms_pipe[1]);
-
-                       reply.cmd = CLVMD_CMD_REPLY;
-                       reply.status = ENOMEM;
-                       reply.arglen = 0;
-                       reply.flags = 0;
+                       struct clvm_header reply = {
+                               .cmd = CLVMD_CMD_REPLY,
+                               .status = ENOMEM
+                       };
+
+                       (void) close(comms_pipe[0]);
+                       (void) close(comms_pipe[1]);
+
                        send_message(&reply, sizeof(reply), our_csid,
                                     thisfd->fd,
                                     "Error sending ENOMEM reply to local user");
@@ -1279,8 +1369,8 @@ static int read_from_local_sock(struct local_client *thisfd)
                thisfd->bits.localsock.in_progress = TRUE;
                thisfd->bits.localsock.state = PRE_COMMAND;
                DEBUGLOG("Creating pre&post thread\n");
-               status = pthread_create(&thisfd->bits.localsock.threadid, NULL,
-                              pre_and_post_thread, thisfd);
+               status = pthread_create(&thisfd->bits.localsock.threadid,
+                                       &stack_attr, pre_and_post_thread, thisfd);
                DEBUGLOG("Created pre&post thread, state = %d\n", status);
        }
        return len;
@@ -1306,7 +1396,10 @@ static int distribute_command(struct local_client *thisfd)
        int len = thisfd->bits.localsock.cmd_len;
 
        thisfd->xid = global_xid++;
-       DEBUGLOG("distribute command: XID = %d\n", thisfd->xid);
+       DEBUGLOG("distribute command: XID = %d, flags=0x%x (%s%s)\n",
+                thisfd->xid, inheader->flags,
+               (inheader->flags & CLVMD_FLAG_LOCAL) ? "LOCAL" : "",
+               (inheader->flags & CLVMD_FLAG_REMOTE) ? "REMOTE" : "");
 
        /* Forward it to other nodes in the cluster if needed */
        if (!(inheader->flags & CLVMD_FLAG_LOCAL)) {
@@ -1319,7 +1412,11 @@ static int distribute_command(struct local_client *thisfd)
                        thisfd->bits.localsock.in_progress = TRUE;
                        thisfd->bits.localsock.sent_out = TRUE;
 
-                       /* Do it here first */
+                       /*
+                        * Send to local node first, even if CLVMD_FLAG_REMOTE
+                        * is set so we still get a reply if this is the
+                        * only node.
+                        */
                        add_to_lvmqueue(thisfd, inheader, len, NULL);
 
                        DEBUGLOG("Sending message to all cluster nodes\n");
@@ -1372,7 +1469,6 @@ static void process_remote_command(struct clvm_header *msg, int msglen, int fd,
        int replylen = 0;
        int buflen = max_cluster_message - sizeof(struct clvm_header) - 1;
        int status;
-       int msg_malloced = 0;
 
        /* Get the node name as we /may/ need it later */
        clops->name_from_csid(csid, nodename);
@@ -1431,9 +1527,9 @@ static void process_remote_command(struct clvm_header *msg, int msglen, int fd,
 
        if (replyargs != NULL) {
                /* Run the command */
-               status =
-                   do_command(NULL, msg, msglen, &replyargs, buflen,
-                              &replylen);
+               /* FIXME: usage of init_test() is unprotected */
+               status = do_command(NULL, msg, msglen, &replyargs,
+                                   buflen, &replylen);
        } else {
                status = ENOMEM;
        }
@@ -1481,10 +1577,6 @@ static void process_remote_command(struct clvm_header *msg, int msglen, int fd,
                }
        }
 
-       /* Free buffer if it was malloced */
-       if (msg_malloced) {
-               free(msg);
-       }
        free(replyargs);
 }
 
@@ -1554,11 +1646,6 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
        DEBUGLOG("in sub thread: client = %p\n", client);
        pthread_mutex_lock(&client->bits.localsock.mutex);
 
-       /* Don't start until the LVM thread is ready */
-       pthread_mutex_lock(&lvm_start_mutex);
-       pthread_mutex_unlock(&lvm_start_mutex);
-       DEBUGLOG("Sub thread ready for work.\n");
-
        /* Ignore SIGUSR1 (handled by master process) but enable
           SIGUSR2 (kills subthreads) */
        sigemptyset(&ss);
@@ -1572,6 +1659,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
        /* Loop around doing PRE and POST functions until the client goes away */
        while (!client->bits.localsock.finished) {
                /* Execute the code */
+               /* FIXME: usage of init_test() is unprotected as in do_command() */
                status = do_pre_command(client);
 
                if (status)
@@ -1654,7 +1742,12 @@ static int process_local_command(struct clvm_header *msg, int msglen,
        if (replybuf == NULL)
                return -1;
 
-       status = do_command(client, msg, msglen, &replybuf, buflen, &replylen);
+       /* If remote flag is set, just set a successful status code. */
+       if (msg->flags & CLVMD_FLAG_REMOTE)
+               status = 0;
+       else
+               /* FIXME: usage of init_test() is unprotected */
+               status = do_command(client, msg, msglen, &replybuf, buflen, &replylen);
 
        if (status)
                client->bits.localsock.all_success = 0;
@@ -1723,13 +1816,18 @@ static void send_local_reply(struct local_client *client, int status, int fd)
        }
 
        /* Add in the size of our header */
-       message_len = message_len + sizeof(struct clvm_header) + 1;
-       replybuf = malloc(message_len);
+       message_len = message_len + sizeof(struct clvm_header);
+       if (!(replybuf = malloc(message_len))) {
+               DEBUGLOG("Memory allocation fails\n");
+               return;
+       }
 
        clientreply = (struct clvm_header *) replybuf;
        clientreply->status = status;
        clientreply->cmd = CLVMD_CMD_REPLY;
        clientreply->node[0] = '\0';
+       clientreply->xid = 0;
+       clientreply->clientid = 0;
        clientreply->flags = 0;
 
        ptr = clientreply->args;
@@ -1764,7 +1862,7 @@ static void send_local_reply(struct local_client *client, int status, int fd)
        /* Terminate with an empty node name */
        *ptr = '\0';
 
-       clientreply->arglen = ptr - clientreply->args + 1;
+       clientreply->arglen = ptr - clientreply->args;
 
        /* And send it */
        send_message(replybuf, message_len, our_csid, fd,
@@ -1795,7 +1893,7 @@ static void free_reply(struct local_client *client)
 }
 
 /* Send our version number to the cluster */
-static void send_version_message()
+static void send_version_message(void)
 {
        char message[sizeof(struct clvm_header) + sizeof(int) * 3];
        struct clvm_header *msg = (struct clvm_header *) message;
@@ -1847,7 +1945,7 @@ static int send_message(void *buf, int msglen, const char *csid, int fd,
                                break;
                        }
 
-                       len = write(fd, buf + ptr, msglen - ptr);
+                       len = write(fd, (char*)buf + ptr, msglen - ptr);
 
                        if (len <= 0) {
                                if (errno == EINTR)
@@ -1900,11 +1998,11 @@ static int process_work_item(struct lvm_thread_cmd *cmd)
 /*
  * Routine that runs in the "LVM thread".
  */
-static void lvm_thread_fn(void *arg)
+static void *lvm_thread_fn(void *arg)
 {
-       struct dm_list *cmdl, *tmp;
        sigset_t ss;
        struct lvm_startup_params *lvm_params = arg;
+       struct lvm_thread_cmd *cmd;
 
        DEBUGLOG("LVM thread function started\n");
 
@@ -1915,24 +2013,22 @@ static void lvm_thread_fn(void *arg)
        pthread_sigmask(SIG_BLOCK, &ss, NULL);
 
        /* Initialise the interface to liblvm */
-       init_clvm(lvm_params->using_gulm, lvm_params->argv);
+       init_clvm(lvm_params->excl_uuid);
 
        /* Allow others to get moving */
-       pthread_mutex_unlock(&lvm_start_mutex);
+       pthread_barrier_wait(&lvm_start_barrier);
+       DEBUGLOG("Sub thread ready for work.\n");
 
        /* Now wait for some actual work */
-       for (;;) {
-               DEBUGLOG("LVM thread waiting for work\n");
+       pthread_mutex_lock(&lvm_thread_mutex);
 
-               pthread_mutex_lock(&lvm_thread_mutex);
-               if (dm_list_empty(&lvm_cmd_head))
+       while (!quit) {
+               if (dm_list_empty(&lvm_cmd_head)) {
+                       DEBUGLOG("LVM thread waiting for work\n");
                        pthread_cond_wait(&lvm_thread_cond, &lvm_thread_mutex);
-
-               dm_list_iterate_safe(cmdl, tmp, &lvm_cmd_head) {
-                       struct lvm_thread_cmd *cmd;
-
-                       cmd =
-                           dm_list_struct_base(cmdl, struct lvm_thread_cmd, list);
+               } else {
+                       cmd = dm_list_item(dm_list_first(&lvm_cmd_head),
+                                          struct lvm_thread_cmd);
                        dm_list_del(&cmd->list);
                        pthread_mutex_unlock(&lvm_thread_mutex);
 
@@ -1942,8 +2038,11 @@ static void lvm_thread_fn(void *arg)
 
                        pthread_mutex_lock(&lvm_thread_mutex);
                }
-               pthread_mutex_unlock(&lvm_thread_mutex);
        }
+
+       pthread_mutex_unlock(&lvm_thread_mutex);
+
+       pthread_exit(NULL);
 }
 
 /* Pass down some work to the LVM thread */
@@ -1994,42 +2093,52 @@ static int add_to_lvmqueue(struct local_client *client, struct clvm_header *msg,
 static int check_local_clvmd(void)
 {
        int local_socket;
-       struct sockaddr_un sockaddr;
        int ret = 0;
+       struct sockaddr_un sockaddr = { .sun_family = AF_UNIX };
+
+       if (!dm_strncpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(sockaddr.sun_path))) {
+               log_error("%s: clvmd socket name too long.", CLVMD_SOCKNAME);
+               return -1;
+       }
 
        /* Open local socket */
        if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
+               log_sys_error("socket", "local socket");
                return -1;
        }
 
-       memset(&sockaddr, 0, sizeof(sockaddr));
-       memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME));
-       sockaddr.sun_family = AF_UNIX;
-
        if (connect(local_socket,(struct sockaddr *) &sockaddr,
                    sizeof(sockaddr))) {
+               log_sys_error("connect", "local socket");
                ret = -1;
        }
 
-       close(local_socket);
+       if (close(local_socket))
+               log_sys_error("close", "local socket");
+
        return ret;
 }
 
 static void close_local_sock(int local_socket)
 {
        if (local_socket != -1 && close(local_socket))
-               stack;
+               log_sys_error("close", CLVMD_SOCKNAME);
 
        if (CLVMD_SOCKNAME[0] != '\0' && unlink(CLVMD_SOCKNAME))
                stack;
 }
 
 /* Open the local socket, that's the one we talk to libclvm down */
-static int open_local_sock()
+static int open_local_sock(void)
 {
-       int local_socket = -1;
-       struct sockaddr_un sockaddr;
        mode_t old_mask;
+       int local_socket = -1;
+       struct sockaddr_un sockaddr = { .sun_family = AF_UNIX };
+
+       if (!dm_strncpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(sockaddr.sun_path))) {
+               log_error("%s: clvmd socket name too long.", CLVMD_SOCKNAME);
+               return -1;
+       }
 
        close_local_sock(local_socket);
 
@@ -2046,11 +2155,9 @@ static int open_local_sock()
        /* Set Close-on-exec & non-blocking */
        if (fcntl(local_socket, F_SETFD, 1))
                DEBUGLOG("setting CLOEXEC on local_socket failed: %s\n", strerror(errno));
-       fcntl(local_socket, F_SETFL, fcntl(local_socket, F_GETFL, 0) | O_NONBLOCK);
+       if (fcntl(local_socket, F_SETFL, fcntl(local_socket, F_GETFL, 0) | O_NONBLOCK))
+               DEBUGLOG("setting O_NONBLOCK on local_socket failed: %s\n", strerror(errno));
 
-       memset(&sockaddr, 0, sizeof(sockaddr));
-       memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME));
-       sockaddr.sun_family = AF_UNIX;
 
        if (bind(local_socket, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) {
                log_error("can't bind local socket: %m");
@@ -2071,7 +2178,7 @@ error:
        return -1;
 }
 
-void process_message(struct local_client *client, const char *buf, int len,
+void process_message(struct local_client *client, char *buf, int len,
                     const char *csid)
 {
        struct clvm_header *inheader;
@@ -2108,7 +2215,7 @@ static struct local_client *find_client(int clientid)
 {
        struct local_client *thisfd;
        for (thisfd = &local_client_head; thisfd != NULL; thisfd = thisfd->next) {
-               if (thisfd->fd == ntohl(clientid))
+               if (thisfd->fd == (int)ntohl(clientid))
                        return thisfd;
        }
        return NULL;
@@ -2170,8 +2277,6 @@ static if_type_t parse_cluster_interface(char *ifname)
                iface = IF_AUTO;
        if (!strcmp(ifname, "cman"))
                iface = IF_CMAN;
-       if (!strcmp(ifname, "gulm"))
-               iface = IF_GULM;
        if (!strcmp(ifname, "openais"))
                iface = IF_OPENAIS;
        if (!strcmp(ifname, "corosync"))
@@ -2187,7 +2292,7 @@ static if_type_t parse_cluster_interface(char *ifname)
  * only called if the command-line option is not present, and if it fails
  * we still try the interfaces in order.
  */
-static if_type_t get_cluster_type()
+static if_type_t get_cluster_type(void)
 {
 #ifdef HAVE_COROSYNC_CONFDB_H
        confdb_handle_t handle;
@@ -2227,6 +2332,9 @@ static if_type_t get_cluster_type()
         if (result != CS_OK)
                goto out;
 
+       if (namelen >= sizeof(buf))
+               namelen = sizeof(buf) - 1;
+
        buf[namelen] = '\0';
        type = parse_cluster_interface(buf);
        DEBUGLOG("got interface type '%s' from confdb\n", buf);
index ccc79cc342c57fedf136b95ad9b0c23be31c1fd0..5bad43aca91267b293d1378be99f50f78972a3c5 100644 (file)
@@ -112,11 +112,14 @@ extern void cmd_client_cleanup(struct local_client *client);
 extern int add_client(struct local_client *new_client);
 
 extern void clvmd_cluster_init_completed(void);
-extern void process_message(struct local_client *client, const char *buf,
+extern void process_message(struct local_client *client, char *buf,
                            int len, const char *csid);
 extern void debuglog(const char *fmt, ... )
   __attribute__ ((format(printf, 1, 2)));
 
+void clvmd_set_debug(debug_t new_de);
+debug_t clvmd_get_debug(void);
+
 int sync_lock(const char *resource, int mode, int flags, int *lockid);
 int sync_unlock(const char *resource, int lockid);
 
index 214f2295529a427b5f43affc673fbba6d97457f1..6793752445700ce9d46fad62c662d34e36e3384d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -109,10 +109,9 @@ static const char *decode_full_locking_cmd(uint32_t cmdl)
                break;
        }
 
-       sprintf(buf, "0x%x %s (%s|%s%s%s%s%s%s)", cmdl, command, type, scope,
+       sprintf(buf, "0x%x %s (%s|%s%s%s%s%s)", cmdl, command, type, scope,
                cmdl & LCK_NONBLOCK   ? "|NONBLOCK" : "",
                cmdl & LCK_HOLD       ? "|HOLD" : "",
-               cmdl & LCK_LOCAL      ? "|LOCAL" : "",
                cmdl & LCK_CLUSTER_VG ? "|CLUSTER_VG" : "",
                cmdl & LCK_CACHE      ? "|CACHE" : "");
 
@@ -132,12 +131,14 @@ static const char *decode_flags(unsigned char flags)
        static char buf[128];
        int len;
 
-       len = sprintf(buf, "0x%x ( %s%s%s%s%s)", flags,
+       len = sprintf(buf, "0x%x ( %s%s%s%s%s%s%s)", flags,
                flags & LCK_PARTIAL_MODE          ? "PARTIAL_MODE|" : "",
                flags & LCK_MIRROR_NOSYNC_MODE    ? "MIRROR_NOSYNC|" : "",
                flags & LCK_DMEVENTD_MONITOR_MODE ? "DMEVENTD_MONITOR|" : "",
                flags & LCK_ORIGIN_ONLY_MODE ? "ORIGIN_ONLY|" : "",
-               flags & LCK_CONVERT ? "CONVERT|" : "");
+               flags & LCK_TEST_MODE ? "TEST|" : "",
+               flags & LCK_CONVERT ? "CONVERT|" : "",
+               flags & LCK_DMEVENTD_MONITOR_IGNORE ? "DMEVENTD_MONITOR_IGNORE|" : "");
 
        if (len > 1)
                buf[len - 2] = ' ';
@@ -147,7 +148,7 @@ static const char *decode_flags(unsigned char flags)
        return buf;
 }
 
-char *get_last_lvm_error()
+char *get_last_lvm_error(void)
 {
        return last_error;
 }
@@ -166,11 +167,15 @@ static struct lv_info *lookup_info(const char *resource)
        return lvi;
 }
 
-static void insert_info(const char *resource, struct lv_info *lvi)
+static int insert_info(const char *resource, struct lv_info *lvi)
 {
+       int ret;
+
        pthread_mutex_lock(&lv_hash_lock);
-       dm_hash_insert(lv_hash, resource, lvi);
+       ret = dm_hash_insert(lv_hash, resource, lvi);
        pthread_mutex_unlock(&lv_hash_lock);
+
+       return ret;
 }
 
 static void remove_info(const char *resource)
@@ -194,16 +199,16 @@ static int get_current_lock(char *resource)
 }
 
 
-void init_lvhash()
+void init_lvhash(void)
 {
        /* Create hash table for keeping LV locks & status */
-       lv_hash = dm_hash_create(100);
+       lv_hash = dm_hash_create(1024);
        pthread_mutex_init(&lv_hash_lock, NULL);
        pthread_mutex_init(&lvm_lock, NULL);
 }
 
 /* Called at shutdown to tidy the lockspace */
-void destroy_lvhash()
+void destroy_lvhash(void)
 {
        struct dm_hash_node *v;
        struct lv_info *lvi;
@@ -235,14 +240,25 @@ static int hold_lock(char *resource, int mode, int flags)
        int saved_errno;
        struct lv_info *lvi;
 
+       if (test_mode())
+               return 0;
+
        /* Mask off invalid options */
        flags &= LCKF_NOQUEUE | LCKF_CONVERT;
 
        lvi = lookup_info(resource);
 
-       if (lvi && lvi->lock_mode == mode) {
-               DEBUGLOG("hold_lock, lock mode %d already held\n", mode);
-               return 0;
+       if (lvi) {
+               if (lvi->lock_mode == mode) {
+                       DEBUGLOG("hold_lock, lock mode %d already held\n",
+                                mode);
+                       return 0;
+               }
+               if ((lvi->lock_mode == LCK_EXCL) && (mode == LCK_WRITE)) {
+                       DEBUGLOG("hold_lock, lock already held LCK_EXCL, "
+                                "ignoring LCK_WRITE request");
+                       return 0;
+               }
        }
 
        /* Only allow explicit conversions */
@@ -265,8 +281,10 @@ static int hold_lock(char *resource, int mode, int flags)
                errno = saved_errno;
        } else {
                lvi = malloc(sizeof(struct lv_info));
-               if (!lvi)
+               if (!lvi) {
+                       errno = ENOMEM;
                        return -1;
+               }
 
                lvi->lock_mode = mode;
                status = sync_lock(resource, mode, flags & ~LCKF_CONVERT, &lvi->lock_id);
@@ -276,7 +294,10 @@ static int hold_lock(char *resource, int mode, int flags)
                        DEBUGLOG("hold_lock. lock at %d failed: %s\n", mode,
                                 strerror(errno));
                } else
-                       insert_info(resource, lvi);
+                       if (!insert_info(resource, lvi)) {
+                               errno = ENOMEM;
+                               return -1;
+                       }
 
                errno = saved_errno;
        }
@@ -290,6 +311,9 @@ static int hold_unlock(char *resource)
        int status;
        int saved_errno;
 
+       if (test_mode())
+               return 0;
+
        if (!(lvi = lookup_info(resource))) {
                DEBUGLOG("hold_unlock, lock not already held\n");
                return 0;
@@ -316,7 +340,7 @@ static int hold_unlock(char *resource)
 */
 
 /* Activate LV exclusive or non-exclusive */
-static int do_activate_lv(char *resource, unsigned char lock_flags, int mode)
+static int do_activate_lv(char *resource, unsigned char command, unsigned char lock_flags, int mode)
 {
        int oldmode;
        int status;
@@ -326,7 +350,7 @@ static int do_activate_lv(char *resource, unsigned char lock_flags, int mode)
 
        /* Is it already open ? */
        oldmode = get_current_lock(resource);
-       if (oldmode == mode && (lock_flags & LCK_CLUSTER_VG)) {
+       if (oldmode == mode && (command & LCK_CLUSTER_VG)) {
                DEBUGLOG("do_activate_lv, lock already held at %d\n", oldmode);
                return 0;       /* Nothing to do */
        }
@@ -349,7 +373,7 @@ static int do_activate_lv(char *resource, unsigned char lock_flags, int mode)
         * Use lock conversion only if requested, to prevent implicit conversion
         * of exclusive lock to shared one during activation.
         */
-       if (lock_flags & LCK_CLUSTER_VG) {
+       if (command & LCK_CLUSTER_VG) {
                status = hold_lock(resource, mode, LCKF_NOQUEUE | (lock_flags & LCK_CONVERT ? LCKF_CONVERT:0));
                if (status) {
                        /* Return an LVM-sensible error for this.
@@ -369,9 +393,9 @@ static int do_activate_lv(char *resource, unsigned char lock_flags, int mode)
                goto error;
 
        if (lvi.suspended) {
-               memlock_inc(cmd);
+               critical_section_inc(cmd, "resuming");
                if (!lv_resume(cmd, resource, 0)) {
-                       memlock_dec(cmd);
+                       critical_section_dec(cmd, "resumed");
                        goto error;
                }
        }
@@ -389,55 +413,62 @@ error:
 }
 
 /* Resume the LV if it was active */
-static int do_resume_lv(char *resource, unsigned char lock_flags)
+static int do_resume_lv(char *resource, unsigned char command, unsigned char lock_flags)
 {
-       int oldmode;
+       int oldmode, origin_only, exclusive, revert;
 
        /* Is it open ? */
        oldmode = get_current_lock(resource);
-       if (oldmode == -1 && (lock_flags & LCK_CLUSTER_VG)) {
+       if (oldmode == -1 && (command & LCK_CLUSTER_VG)) {
                DEBUGLOG("do_resume_lv, lock not already held\n");
                return 0;       /* We don't need to do anything */
        }
+       origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0;
+       exclusive = (oldmode == LCK_EXCL) ? 1 : 0;
+       revert = (lock_flags & LCK_REVERT_MODE) ? 1 : 0;
 
-       if (!lv_resume_if_active(cmd, resource, (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0))
+       if (!lv_resume_if_active(cmd, resource, origin_only, exclusive, revert))
                return EIO;
 
        return 0;
 }
 
 /* Suspend the device if active */
-static int do_suspend_lv(char *resource, unsigned char lock_flags)
+static int do_suspend_lv(char *resource, unsigned char command, unsigned char lock_flags)
 {
        int oldmode;
        struct lvinfo lvi;
        unsigned origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0;
+       unsigned exclusive;
 
        /* Is it open ? */
        oldmode = get_current_lock(resource);
-       if (oldmode == -1 && (lock_flags & LCK_CLUSTER_VG)) {
+       if (oldmode == -1 && (command & LCK_CLUSTER_VG)) {
                DEBUGLOG("do_suspend_lv, lock not already held\n");
                return 0; /* Not active, so it's OK */
        }
 
+       exclusive = (oldmode == LCK_EXCL) ? 1 : 0;
+
        /* Only suspend it if it exists */
        if (!lv_info_by_lvid(cmd, resource, origin_only, &lvi, 0, 0))
                return EIO;
 
-       if (lvi.exists && !lv_suspend_if_active(cmd, resource, origin_only))
+       if (lvi.exists &&
+           !lv_suspend_if_active(cmd, resource, origin_only, exclusive))
                return EIO;
 
        return 0;
 }
 
-static int do_deactivate_lv(char *resource, unsigned char lock_flags)
+static int do_deactivate_lv(char *resource, unsigned char command, unsigned char lock_flags)
 {
        int oldmode;
        int status;
 
        /* Is it open ? */
        oldmode = get_current_lock(resource);
-       if (oldmode == -1 && (lock_flags & LCK_CLUSTER_VG)) {
+       if (oldmode == -1 && (command & LCK_CLUSTER_VG)) {
                DEBUGLOG("do_deactivate_lock, lock not already held\n");
                return 0;       /* We don't need to do anything */
        }
@@ -445,7 +476,7 @@ static int do_deactivate_lv(char *resource, unsigned char lock_flags)
        if (!lv_deactivate(cmd, resource))
                return EIO;
 
-       if (lock_flags & LCK_CLUSTER_VG) {
+       if (command & LCK_CLUSTER_VG) {
                status = hold_unlock(resource);
                if (status)
                        return errno;
@@ -479,8 +510,8 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
 {
        int status = 0;
 
-       DEBUGLOG("do_lock_lv: resource '%s', cmd = %s, flags = %s, memlock = %d\n",
-                resource, decode_locking_cmd(command), decode_flags(lock_flags), memlock());
+       DEBUGLOG("do_lock_lv: resource '%s', cmd = %s, flags = %s, critical_section = %d\n",
+                resource, decode_locking_cmd(command), decode_flags(lock_flags), critical_section());
 
        if (!cmd->config_valid || config_files_changed(cmd)) {
                /* Reinitialise various settings inc. logging, filters */
@@ -494,10 +525,14 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
        if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
                init_mirror_in_sync(1);
 
-       if (lock_flags & LCK_DMEVENTD_MONITOR_MODE)
-               init_dmeventd_monitor(1);
-       else
-               init_dmeventd_monitor(0);
+       if (lock_flags & LCK_DMEVENTD_MONITOR_IGNORE)
+               init_dmeventd_monitor(DMEVENTD_MONITOR_IGNORE);
+       else {
+               if (lock_flags & LCK_DMEVENTD_MONITOR_MODE)
+                       init_dmeventd_monitor(1);
+               else
+                       init_dmeventd_monitor(0);
+       }
 
        cmd->partial_activation = (lock_flags & LCK_PARTIAL_MODE) ? 1 : 0;
 
@@ -506,24 +541,24 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
 
        switch (command & LCK_MASK) {
        case LCK_LV_EXCLUSIVE:
-               status = do_activate_lv(resource, lock_flags, LCK_EXCL);
+               status = do_activate_lv(resource, command, lock_flags, LCK_EXCL);
                break;
 
        case LCK_LV_SUSPEND:
-               status = do_suspend_lv(resource, lock_flags);
+               status = do_suspend_lv(resource, command, lock_flags);
                break;
 
        case LCK_UNLOCK:
        case LCK_LV_RESUME:     /* if active */
-               status = do_resume_lv(resource, lock_flags);
+               status = do_resume_lv(resource, command, lock_flags);
                break;
 
        case LCK_LV_ACTIVATE:
-               status = do_activate_lv(resource, lock_flags, LCK_READ);
+               status = do_activate_lv(resource, command, lock_flags, LCK_READ);
                break;
 
        case LCK_LV_DEACTIVATE:
-               status = do_deactivate_lv(resource, lock_flags);
+               status = do_deactivate_lv(resource, command, lock_flags);
                break;
 
        default:
@@ -541,7 +576,7 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
        dm_pool_empty(cmd->mem);
        pthread_mutex_unlock(&lvm_lock);
 
-       DEBUGLOG("Command return is %d, memlock is %d\n", status, memlock());
+       DEBUGLOG("Command return is %d, critical_section is %d\n", status, critical_section());
        return status;
 }
 
@@ -554,7 +589,7 @@ int pre_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
           LCKF_CONVERT is used always, local node is going to modify metadata
         */
        if ((command & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) == LCK_LV_SUSPEND &&
-           (lock_flags & LCK_CLUSTER_VG)) {
+           (command & LCK_CLUSTER_VG)) {
                DEBUGLOG("pre_lock_lv: resource '%s', cmd = %s, flags = %s\n",
                         resource, decode_locking_cmd(command), decode_flags(lock_flags));
 
@@ -573,7 +608,7 @@ int post_lock_lv(unsigned char command, unsigned char lock_flags,
 
        /* Opposite of above, done on resume after a metadata update */
        if ((command & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) == LCK_LV_RESUME &&
-           (lock_flags & LCK_CLUSTER_VG)) {
+           (command & LCK_CLUSTER_VG)) {
                int oldmode;
 
                DEBUGLOG
@@ -611,7 +646,7 @@ int do_check_lvm1(const char *vgname)
        return status == 1 ? 0 : EBUSY;
 }
 
-int do_refresh_cache()
+int do_refresh_cache(void)
 {
        DEBUGLOG("Refreshing context\n");
        log_notice("Refreshing context");
@@ -633,46 +668,6 @@ int do_refresh_cache()
        return 0;
 }
 
-
-/* Only called at gulm startup. Drop any leftover VG or P_orphan locks
-   that might be hanging around if we died for any reason
-*/
-static void drop_vg_locks(void)
-{
-       char vg[128];
-       char line[255];
-       FILE *vgs =
-           popen
-           (LVM_PATH " pvs  --config 'log{command_names=0 prefix=\"\"}' --nolocking --noheadings -o vg_name", "r");
-
-       sync_unlock("P_" VG_ORPHANS, LCK_EXCL);
-       sync_unlock("P_" VG_GLOBAL, LCK_EXCL);
-
-       if (!vgs)
-               return;
-
-       while (fgets(line, sizeof(line), vgs)) {
-               char *vgend;
-               char *vgstart;
-
-               if (line[strlen(line)-1] == '\n')
-                       line[strlen(line)-1] = '\0';
-
-               vgstart = line + strspn(line, " ");
-               vgend = vgstart + strcspn(vgstart, " ");
-               *vgend = '\0';
-
-               if (strncmp(vgstart, "WARNING:", 8) == 0)
-                       continue;
-
-               sprintf(vg, "V_%s", vgstart);
-               sync_unlock(vg, LCK_EXCL);
-
-       }
-       if (fclose(vgs))
-               DEBUGLOG("vgs fclose failed: %s\n", strerror(errno));
-}
-
 /*
  * Handle VG lock - drop metadata or update lvmcache state
  */
@@ -689,8 +684,8 @@ void do_lock_vg(unsigned char command, unsigned char lock_flags, char *resource)
        if (strncmp(resource, "P_#", 3) && !strncmp(resource, "P_", 2))
                lock_cmd |= LCK_CACHE;
 
-       DEBUGLOG("do_lock_vg: resource '%s', cmd = %s, flags = %s, memlock = %d\n",
-                resource, decode_full_locking_cmd(lock_cmd), decode_flags(lock_flags), memlock());
+       DEBUGLOG("do_lock_vg: resource '%s', cmd = %s, flags = %s, critical_section = %d\n",
+                resource, decode_full_locking_cmd(lock_cmd), decode_flags(lock_flags), critical_section());
 
        /* P_#global causes a full cache refresh */
        if (!strcmp(resource, "P_" VG_GLOBAL)) {
@@ -716,50 +711,34 @@ void do_lock_vg(unsigned char command, unsigned char lock_flags, char *resource)
        pthread_mutex_unlock(&lvm_lock);
 }
 
-/*
- * Compare the uuid with the list of exclusive locks that clvmd
- * held before it was restarted, so we can get the right kind
- * of lock now we are restarting.
- */
-static int was_ex_lock(char *uuid, char **argv)
-{
-       int optnum = 0;
-       char *opt = argv[optnum];
-
-       while (opt) {
-               if (strcmp(opt, "-E") == 0) {
-                       opt = argv[++optnum];
-                       if (opt && (strcmp(opt, uuid) == 0)) {
-                               DEBUGLOG("Lock %s is exclusive\n", uuid);
-                               return 1;
-                       }
-               }
-               opt = argv[++optnum];
-       }
-       return 0;
-}
-
 /*
  * Ideally, clvmd should be started before any LVs are active
  * but this may not be the case...
  * I suppose this also comes in handy if clvmd crashes, not that it would!
  */
-static void *get_initial_state(char **argv)
+static int get_initial_state(struct dm_hash_table *excl_uuid)
 {
        int lock_mode;
        char lv[64], vg[64], flags[25], vg_flags[25];
        char uuid[65];
        char line[255];
-       FILE *lvs =
-           popen
-           (LVM_PATH " lvs  --config 'log{command_names=0 prefix=\"\"}' --nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr,vg_attr",
-            "r");
-
-       if (!lvs)
-               return NULL;
+       char *lvs_cmd;
+       const char *lvm_binary = getenv("LVM_BINARY") ? : LVM_PATH;
+       FILE *lvs;
+
+       if (dm_asprintf(&lvs_cmd, "%s lvs  --config 'log{command_names=0 prefix=\"\"}' "
+                       "--nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr,vg_attr",
+                       lvm_binary) < 0)
+               return_0;
+
+       /* FIXME: Maybe link and use liblvm2cmd directly instead of fork */
+       if (!(lvs = popen(lvs_cmd, "r"))) {
+               dm_free(lvs_cmd);
+               return 0;
+       }
 
        while (fgets(line, sizeof(line), lvs)) {
-               if (sscanf(line, "%s %s %s %s\n", vg, lv, flags, vg_flags) == 4) {
+               if (sscanf(line, "%64s %64s %25s %25s\n", vg, lv, flags, vg_flags) == 4) {
 
                        /* States: s:suspended a:active S:dropped snapshot I:invalid snapshot */
                        if (strlen(vg) == 38 &&                         /* is is a valid UUID ? */
@@ -782,21 +761,23 @@ static void *get_initial_state(char **argv)
                                memcpy(&uuid[58], &lv[32], 6);
                                uuid[64] = '\0';
 
-                               lock_mode = LCK_READ;
-
                                /* Look for this lock in the list of EX locks
                                   we were passed on the command-line */
-                               if (was_ex_lock(uuid, argv))
-                                       lock_mode = LCK_EXCL;
+                               lock_mode = (dm_hash_lookup(excl_uuid, uuid)) ?
+                                       LCK_EXCL : LCK_READ;
 
                                DEBUGLOG("getting initial lock for %s\n", uuid);
-                               hold_lock(uuid, lock_mode, LCKF_NOQUEUE);
+                               if (hold_lock(uuid, lock_mode, LCKF_NOQUEUE))
+                                       DEBUGLOG("Failed to hold lock %s\n", uuid);
                        }
                }
        }
        if (fclose(lvs))
                DEBUGLOG("lvs fclose failed: %s\n", strerror(errno));
-       return NULL;
+
+       dm_free(lvs_cmd);
+
+       return 1;
 }
 
 static void lvm2_log_fn(int level, const char *file, int line, int dm_errno,
@@ -863,7 +844,7 @@ void lvm_do_backup(const char *vgname)
        else
                log_error("Error backing up metadata, can't find VG for group %s", vgname);
 
-       free_vg(vg);
+       release_vg(vg);
        dm_pool_empty(cmd->mem);
 
        pthread_mutex_unlock(&lvm_lock);
@@ -894,10 +875,26 @@ struct dm_hash_node *get_next_excl_lock(struct dm_hash_node *v, char **name)
        return v;
 }
 
+void lvm_do_fs_unlock(void)
+{
+       pthread_mutex_lock(&lvm_lock);
+       DEBUGLOG("Syncing device names\n");
+       fs_unlock();
+       pthread_mutex_unlock(&lvm_lock);
+}
+
 /* Called to initialise the LVM context of the daemon */
-int init_clvm(int using_gulm, char **argv)
+int init_clvm(struct dm_hash_table *excl_uuid)
 {
-       if (!(cmd = create_toolcontext(1, NULL))) {
+       /* Use LOG_DAEMON for syslog messages instead of LOG_USER */
+       init_syslog(LOG_DAEMON);
+       openlog("clvmd", LOG_PID, LOG_DAEMON);
+
+       /* Initialise already held locks */
+       if (!get_initial_state(excl_uuid))
+               log_error("Cannot load initial lock states.");
+
+       if (!(cmd = create_toolcontext(1, NULL, 0, 1))) {
                log_error("Failed to allocate command context");
                return 0;
        }
@@ -907,21 +904,12 @@ int init_clvm(int using_gulm, char **argv)
                return 0;
        }
 
-       /* Use LOG_DAEMON for syslog messages instead of LOG_USER */
-       init_syslog(LOG_DAEMON);
-       openlog("clvmd", LOG_PID, LOG_DAEMON);
        cmd->cmd_line = "clvmd";
 
        /* Check lvm.conf is setup for cluster-LVM */
        check_config();
        init_ignore_suspended_devices(1);
 
-       /* Remove any non-LV locks that may have been left around */
-       if (using_gulm)
-               drop_vg_locks();
-
-       get_initial_state(argv);
-
        /* Trap log messages so we can pass them back to the user */
        init_log_fn(lvm2_log_fn);
        memlock_inc_daemon(cmd);
index 97153d49e3ba8f635ebf3491caa7a94716e4be37..565f878d77e98afc90f0951d51d54f6c21e807ce 100644 (file)
@@ -27,7 +27,7 @@ extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
                        char *resource);
 extern int do_check_lvm1(const char *vgname);
 extern int do_refresh_cache(void);
-extern int init_clvm(int using_gulm, char **argv);
+extern int init_clvm(struct dm_hash_table *excl_uuid);
 extern void destroy_lvm(void);
 extern void init_lvhash(void);
 extern void destroy_lvhash(void);
@@ -36,5 +36,6 @@ extern char *get_last_lvm_error(void);
 extern void do_lock_vg(unsigned char command, unsigned char lock_flags,
                      char *resource);
 extern struct dm_hash_node *get_next_excl_lock(struct dm_hash_node *v, char **name);
+void lvm_do_fs_unlock(void);
 
 #endif
index 1e88b5cc80c43d30c19b9527ef2586e64943c755..28b5625f2e0ef1302706909eb5fec0750c377063 100644 (file)
@@ -13,6 +13,8 @@
  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+/* FIXME Remove duplicated functions from this file. */
+
 /*
  * Send a command to a running clvmd from the command-line
  */
@@ -45,7 +47,12 @@ static int _clvmd_sock = -1;
 static int _open_local_sock(void)
 {
        int local_socket;
-       struct sockaddr_un sockaddr;
+       struct sockaddr_un sockaddr = { .sun_family = AF_UNIX };
+
+       if (!dm_strncpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(sockaddr.sun_path))) {
+               fprintf(stderr, "%s: clvmd socket name too long.", CLVMD_SOCKNAME);
+               return -1;
+       }
 
        /* Open local socket */
        if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
@@ -53,11 +60,6 @@ static int _open_local_sock(void)
                return -1;
        }
 
-       memset(&sockaddr, 0, sizeof(sockaddr));
-       memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME));
-
-       sockaddr.sun_family = AF_UNIX;
-
        if (connect(local_socket,(struct sockaddr *) &sockaddr,
                    sizeof(sockaddr))) {
                int saved_errno = errno;
@@ -80,7 +82,7 @@ static int _send_request(const char *inbuf, int inlen, char **retbuf, int no_res
        char outbuf[PIPE_BUF];
        struct clvm_header *outheader = (struct clvm_header *) outbuf;
        int len;
-       int off;
+       unsigned off;
        int buflen;
        int err;
 
@@ -149,29 +151,31 @@ static int _send_request(const char *inbuf, int inlen, char **retbuf, int no_res
 
 /* Build the structure header and parse-out wildcard node names */
 static void _build_header(struct clvm_header *head, int cmd, const char *node,
-                         int len)
+                         unsigned int len)
 {
        head->cmd = cmd;
        head->status = 0;
        head->flags = 0;
+       head->xid = 0;
        head->clientid = 0;
-       head->arglen = len;
-
-       if (node) {
-               /*
-                * Allow a couple of special node names:
-                * "*" for all nodes,
-                * "." for the local node only
-                */
-               if (strcmp(node, "*") == 0) {
-                       head->node[0] = '\0';
-               } else if (strcmp(node, ".") == 0) {
-                       head->node[0] = '\0';
-                       head->flags = CLVMD_FLAG_LOCAL;
-               } else
-                       strcpy(head->node, node);
-       } else
+       if (len)
+               /* 1 byte is used from struct clvm_header.args[1], so -> len - 1 */
+               head->arglen = len - 1;
+       else {
+               head->arglen = 0;
+               *head->args = '\0';
+       }
+
+       /*
+        * Translate special node names.
+        */
+       if (!node || !strcmp(node, NODE_ALL))
+               head->node[0] = '\0';
+       else if (!strcmp(node, NODE_LOCAL)) {
                head->node[0] = '\0';
+               head->flags = CLVMD_FLAG_LOCAL;
+       } else
+               strcpy(head->node, node);
 }
 
 /*
@@ -198,7 +202,8 @@ static int _cluster_request(char cmd, const char *node, void *data, int len,
                return 0;
 
        _build_header(head, cmd, node, len);
-       memcpy(head->node + strlen(head->node) + 1, data, len);
+       if (len)
+               memcpy(head->node + strlen(head->node) + 1, data, len);
 
        status = _send_request(outbuf, sizeof(struct clvm_header) +
                               strlen(head->node) + len, &retbuf, no_response);
@@ -290,7 +295,7 @@ int refresh_clvmd(int all_nodes)
        int status;
        int i;
 
-       status = _cluster_request(CLVMD_CMD_REFRESH, all_nodes?"*":".", args, 0, &response, &num_responses, 0);
+       status = _cluster_request(CLVMD_CMD_REFRESH, all_nodes ? NODE_ALL : NODE_LOCAL, args, 0, &response, &num_responses, 0);
 
        /* If any nodes were down then display them and return an error */
        for (i = 0; i < num_responses; i++) {
@@ -321,7 +326,7 @@ int restart_clvmd(int all_nodes)
 {
        int dummy, status;
 
-       status = _cluster_request(CLVMD_CMD_RESTART, all_nodes?"*":".", NULL, 0, NULL, &dummy, 1);
+       status = _cluster_request(CLVMD_CMD_RESTART, all_nodes ? NODE_ALL : NODE_LOCAL, NULL, 0, NULL, &dummy, 1);
 
        /*
         * FIXME: we cannot receive response, clvmd re-exec before it.
@@ -348,9 +353,9 @@ int debug_clvmd(int level, int clusterwide)
 
        args[0] = level;
        if (clusterwide)
-               nodes = "*";
+               nodes = NODE_ALL;
        else
-               nodes = ".";
+               nodes = NODE_LOCAL;
 
        status = _cluster_request(CLVMD_CMD_SET_DEBUG, nodes, args, 1, &response, &num_responses, 0);
 
diff --git a/daemons/clvmd/tcp-comms.c b/daemons/clvmd/tcp-comms.c
deleted file mode 100644 (file)
index 5f86556..0000000
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- *  Copyright (C) 2002-2003 Sistina Software, Inc. All rights reserved.
- *  Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU Lesser General Public License v.2.1.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/*
- * This provides the inter-clvmd communications for a system without CMAN.
- * There is a listening TCP socket which accepts new connections in the
- * normal way.
- * It can also make outgoing connnections to the other clvmd nodes.
- */
-
-#include "clvmd-common.h"
-
-#include <pthread.h>
-#include <sys/utsname.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <stdint.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <errno.h>
-#include <syslog.h>
-#include <netdb.h>
-#include <assert.h>
-
-#include "clvm.h"
-#include "clvmd-comms.h"
-#include "clvmd.h"
-#include "clvmd-gulm.h"
-
-#define DEFAULT_TCP_PORT 21064
-
-static int listen_fd = -1;
-static int tcp_port;
-struct dm_hash_table *sock_hash;
-
-static int get_our_ip_address(char *addr, int *family);
-static int read_from_tcpsock(struct local_client *fd, char *buf, int len, char *csid,
-                            struct local_client **new_client);
-
-/* Called by init_cluster() to open up the listening socket */
-int init_comms(unsigned short port)
-{
-    struct sockaddr_in6 addr;
-
-    sock_hash = dm_hash_create(100);
-    tcp_port = port ? : DEFAULT_TCP_PORT;
-
-    listen_fd = socket(AF_INET6, SOCK_STREAM, 0);
-
-    if (listen_fd < 0)
-    {
-       return -1;
-    }
-    else
-    {
-       int one = 1;
-       setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
-       setsockopt(listen_fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(int));
-    }
-
-    memset(&addr, 0, sizeof(addr)); // Bind to INADDR_ANY
-    addr.sin6_family = AF_INET6;
-    addr.sin6_port = htons(tcp_port);
-
-    if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
-    {
-       DEBUGLOG("Can't bind to port: %s\n", strerror(errno));
-       syslog(LOG_ERR, "Can't bind to port %d, is clvmd already running ?", tcp_port);
-       close(listen_fd);
-       return -1;
-    }
-
-    listen(listen_fd, 5);
-
-    /* Set Close-on-exec */
-    fcntl(listen_fd, F_SETFD, 1);
-
-    return 0;
-}
-
-void tcp_remove_client(const char *c_csid)
-{
-    struct local_client *client;
-    char csid[GULM_MAX_CSID_LEN];
-    unsigned int i;
-    memcpy(csid, c_csid, sizeof csid);
-    DEBUGLOG("tcp_remove_client\n");
-
-    /* Don't actually close the socket here - that's the
-       job of clvmd.c whch will do the job when it notices the
-       other end has gone. We just need to remove the client(s) from
-       the hash table so we don't try to use it for sending any more */
-    for (i = 0; i < 2; i++)
-    {
-       client = dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
-       if (client)
-       {
-           dm_hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
-           client->removeme = 1;
-           close(client->fd);
-       }
-       /* Look for a mangled one too, on the 2nd iteration. */
-       csid[0] ^= 0x80;
-    }
-}
-
-int alloc_client(int fd, const char *c_csid, struct local_client **new_client)
-{
-    struct local_client *client;
-    char csid[GULM_MAX_CSID_LEN];
-    memcpy(csid, c_csid, sizeof csid);
-
-    DEBUGLOG("alloc_client %d csid = %s\n", fd, print_csid(csid));
-
-    /* Create a local_client and return it */
-    client = malloc(sizeof(struct local_client));
-    if (!client)
-    {
-       DEBUGLOG("malloc failed\n");
-       return -1;
-    }
-
-    memset(client, 0, sizeof(struct local_client));
-    client->fd = fd;
-    client->type = CLUSTER_DATA_SOCK;
-    client->callback = read_from_tcpsock;
-    if (new_client)
-       *new_client = client;
-
-    /* Add to our list of node sockets */
-    if (dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN))
-    {
-       DEBUGLOG("alloc_client mangling CSID for second connection\n");
-       /* This is a duplicate connection but we can't close it because
-          the other end may already have started sending.
-          So, we mangle the IP address and keep it, all sending will
-          go out of the main FD
-       */
-       csid[0] ^= 0x80;
-       client->bits.net.flags = 1; /* indicate mangled CSID */
-
-        /* If it still exists then kill the connection as we should only
-           ever have one incoming connection from each node */
-        if (dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN))
-        {
-           DEBUGLOG("Multiple incoming connections from node\n");
-            syslog(LOG_ERR, " Bogus incoming connection from %d.%d.%d.%d\n", csid[0],csid[1],csid[2],csid[3]);
-
-           free(client);
-            errno = ECONNREFUSED;
-            return -1;
-        }
-    }
-    dm_hash_insert_binary(sock_hash, csid, GULM_MAX_CSID_LEN, client);
-
-    return 0;
-}
-
-int get_main_gulm_cluster_fd()
-{
-    return listen_fd;
-}
-
-
-/* Read on main comms (listen) socket, accept it */
-int cluster_fd_gulm_callback(struct local_client *fd, char *buf, int len, const char *csid,
-                       struct local_client **new_client)
-{
-    int newfd;
-    struct sockaddr_in6 addr;
-    socklen_t addrlen = sizeof(addr);
-    int status;
-    char name[GULM_MAX_CLUSTER_MEMBER_NAME_LEN];
-
-    DEBUGLOG("cluster_fd_callback\n");
-    *new_client = NULL;
-    newfd = accept(listen_fd, (struct sockaddr *)&addr, &addrlen);
-
-    DEBUGLOG("cluster_fd_callback, newfd=%d (errno=%d)\n", newfd, errno);
-    if (!newfd)
-    {
-       syslog(LOG_ERR, "error in accept: %m");
-       errno = EAGAIN;
-       return -1; /* Don't return an error or clvmd will close the listening FD */
-    }
-
-    /* Check that the client is a member of the cluster
-       and reject if not.
-    */
-    if (gulm_name_from_csid((char *)&addr.sin6_addr, name) < 0)
-    {
-       syslog(LOG_ERR, "Got connect from non-cluster node %s\n",
-              print_csid((char *)&addr.sin6_addr));
-       DEBUGLOG("Got connect from non-cluster node %s\n",
-                print_csid((char *)&addr.sin6_addr));
-       close(newfd);
-
-       errno = EAGAIN;
-       return -1;
-    }
-
-    status = alloc_client(newfd, (char *)&addr.sin6_addr, new_client);
-    if (status)
-    {
-       DEBUGLOG("cluster_fd_callback, alloc_client failed, status = %d\n", status);
-       close(newfd);
-       /* See above... */
-       errno = EAGAIN;
-       return -1;
-    }
-    DEBUGLOG("cluster_fd_callback, returning %d, %p\n", newfd, *new_client);
-    return newfd;
-}
-
-/* Try to get at least 'len' bytes from the socket */
-static int really_read(int fd, char *buf, int len)
-{
-       int got, offset;
-
-       got = offset = 0;
-
-       do {
-               got = read(fd, buf+offset, len-offset);
-               DEBUGLOG("really_read. got %d bytes\n", got);
-               offset += got;
-       } while (got > 0 && offset < len);
-
-       if (got < 0)
-               return got;
-       else
-               return offset;
-}
-
-
-static int read_from_tcpsock(struct local_client *client, char *buf, int len, char *csid,
-                            struct local_client **new_client)
-{
-    struct sockaddr_in6 addr;
-    socklen_t slen = sizeof(addr);
-    struct clvm_header *header = (struct clvm_header *)buf;
-    int status;
-    uint32_t arglen;
-
-    DEBUGLOG("read_from_tcpsock fd %d\n", client->fd);
-    *new_client = NULL;
-
-    /* Get "csid" */
-    getpeername(client->fd, (struct sockaddr *)&addr, &slen);
-    memcpy(csid, &addr.sin6_addr, GULM_MAX_CSID_LEN);
-
-    /* Read just the header first, then get the rest if there is any.
-     * Stream sockets, sigh.
-     */
-    status = really_read(client->fd, buf, sizeof(struct clvm_header));
-    if (status > 0)
-    {
-           int status2;
-
-           arglen = ntohl(header->arglen);
-
-           /* Get the rest */
-           if (arglen && arglen < GULM_MAX_CLUSTER_MESSAGE)
-           {
-                   status2 = really_read(client->fd, buf+status, arglen);
-                   if (status2 > 0)
-                           status += status2;
-                   else
-                           status = status2;
-           }
-    }
-
-    DEBUGLOG("read_from_tcpsock, status = %d(errno = %d)\n", status, errno);
-
-    /* Remove it from the hash table if there's an error, clvmd will
-       remove the socket from its lists and free the client struct */
-    if (status == 0 ||
-       (status < 0 && errno != EAGAIN && errno != EINTR))
-    {
-       char remcsid[GULM_MAX_CSID_LEN];
-
-       memcpy(remcsid, csid, GULM_MAX_CSID_LEN);
-       close(client->fd);
-
-       /* If the csid was mangled, then make sure we remove the right entry */
-       if (client->bits.net.flags)
-           remcsid[0] ^= 0x80;
-       dm_hash_remove_binary(sock_hash, remcsid, GULM_MAX_CSID_LEN);
-
-       /* Tell cluster manager layer */
-       add_down_node(remcsid);
-    }
-    else {
-           gulm_add_up_node(csid);
-           /* Send it back to clvmd */
-           process_message(client, buf, status, csid);
-    }
-    return status;
-}
-
-int gulm_connect_csid(const char *csid, struct local_client **newclient)
-{
-    int fd;
-    struct sockaddr_in6 addr;
-    int status;
-    int one = 1;
-
-    DEBUGLOG("Connecting socket\n");
-    fd = socket(PF_INET6, SOCK_STREAM, 0);
-
-    if (fd < 0)
-    {
-       syslog(LOG_ERR, "Unable to create new socket: %m");
-       return -1;
-    }
-
-    addr.sin6_family = AF_INET6;
-    memcpy(&addr.sin6_addr, csid, GULM_MAX_CSID_LEN);
-    addr.sin6_port = htons(tcp_port);
-
-    DEBUGLOG("Connecting socket %d\n", fd);
-    if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)) < 0)
-    {
-       /* "Connection refused" is "normal" because clvmd may not yet be running
-        * on that node.
-        */
-       if (errno != ECONNREFUSED)
-       {
-           syslog(LOG_ERR, "Unable to connect to remote node: %m");
-       }
-       DEBUGLOG("Unable to connect to remote node: %s\n", strerror(errno));
-       close(fd);
-       return -1;
-    }
-
-    /* Set Close-on-exec */
-    fcntl(fd, F_SETFD, 1);
-    setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(int));
-
-    status = alloc_client(fd, csid, newclient);
-    if (status)
-       close(fd);
-    else
-       add_client(*newclient);
-
-    /* If we can connect to it, it must be running a clvmd */
-    gulm_add_up_node(csid);
-    return status;
-}
-
-/* Send a message to a known CSID */
-static int tcp_send_message(void *buf, int msglen, const char *csid, const char *errtext)
-{
-    int status;
-    struct local_client *client;
-    char ourcsid[GULM_MAX_CSID_LEN];
-
-    assert(csid);
-
-    DEBUGLOG("tcp_send_message, csid = %s, msglen = %d\n", print_csid(csid), msglen);
-
-    /* Don't connect to ourself */
-    get_our_gulm_csid(ourcsid);
-    if (memcmp(csid, ourcsid, GULM_MAX_CSID_LEN) == 0)
-       return msglen;
-
-    client = dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
-    if (!client)
-    {
-       status = gulm_connect_csid(csid, &client);
-       if (status)
-           return -1;
-    }
-    DEBUGLOG("tcp_send_message, fd = %d\n", client->fd);
-
-    return write(client->fd, buf, msglen);
-}
-
-
-int gulm_cluster_send_message(void *buf, int msglen, const char *csid, const char *errtext)
-{
-    int status=0;
-
-    DEBUGLOG("cluster send message, csid = %p, msglen = %d\n", csid, msglen);
-
-    /* If csid is NULL then send to all known (not just connected) nodes */
-    if (!csid)
-    {
-       void *context = NULL;
-       char loop_csid[GULM_MAX_CSID_LEN];
-
-       /* Loop round all gulm-known nodes */
-       while (get_next_node_csid(&context, loop_csid))
-       {
-           status = tcp_send_message(buf, msglen, loop_csid, errtext);
-           if (status == 0 ||
-               (status < 0 && (errno == EAGAIN || errno == EINTR)))
-               break;
-       }
-    }
-    else
-    {
-
-       status = tcp_send_message(buf, msglen, csid, errtext);
-    }
-    return status;
-}
-
-/* To get our own IP address we get the locally bound address of the
-   socket that's talking to GULM in the assumption(eek) that it will
-   be on the "right" network in a multi-homed system */
-static int get_our_ip_address(char *addr, int *family)
-{
-       struct utsname info;
-
-       uname(&info);
-       get_ip_address(info.nodename, addr);
-
-       return 0;
-}
-
-/* Public version of above for those that don't care what protocol
-   we're using */
-void get_our_gulm_csid(char *csid)
-{
-    static char our_csid[GULM_MAX_CSID_LEN];
-    static int got_csid = 0;
-
-    if (!got_csid)
-    {
-       int family;
-
-       memset(our_csid, 0, sizeof(our_csid));
-       if (get_our_ip_address(our_csid, &family))
-       {
-           got_csid = 1;
-       }
-    }
-    memcpy(csid, our_csid, GULM_MAX_CSID_LEN);
-}
-
-static void map_v4_to_v6(struct in_addr *ip4, struct in6_addr *ip6)
-{
-   ip6->s6_addr32[0] = 0;
-   ip6->s6_addr32[1] = 0;
-   ip6->s6_addr32[2] = htonl(0xffff);
-   ip6->s6_addr32[3] = ip4->s_addr;
-}
-
-/* Get someone else's IP address from DNS */
-int get_ip_address(const char *node, char *addr)
-{
-    struct hostent *he;
-
-    memset(addr, 0, GULM_MAX_CSID_LEN);
-
-    // TODO: what do we do about multi-homed hosts ???
-    // CCSs ip_interfaces solved this but some bugger removed it.
-
-    /* Try IPv6 first. The man page for gethostbyname implies that
-       it will lookup ip6 & ip4 names, but it seems not to */
-    he = gethostbyname2(node, AF_INET6);
-    if (he)
-    {
-       memcpy(addr, he->h_addr_list[0],
-              he->h_length);
-    }
-    else
-    {
-       he = gethostbyname2(node, AF_INET);
-       if (!he)
-           return -1;
-       map_v4_to_v6((struct in_addr *)he->h_addr_list[0], (struct in6_addr *)addr);
-    }
-
-    return 0;
-}
-
-char *print_csid(const char *csid)
-{
-    static char buf[128];
-    int *icsid = (int *)csid;
-
-    sprintf(buf, "[%x.%x.%x.%x]",
-           icsid[0],icsid[1],icsid[2],icsid[3]);
-
-    return buf;
-}
diff --git a/daemons/clvmd/tcp-comms.h b/daemons/clvmd/tcp-comms.h
deleted file mode 100644 (file)
index 9260e12..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <netinet/in.h>
-
-#define GULM_MAX_CLUSTER_MESSAGE 1600
-#define GULM_MAX_CSID_LEN sizeof(struct in6_addr)
-#define GULM_MAX_CLUSTER_MEMBER_NAME_LEN 128
-
-extern int init_comms(unsigned short);
-extern char *print_csid(const char *);
-int get_main_gulm_cluster_fd(void);
-int cluster_fd_gulm_callback(struct local_client *fd, char *buf, int len, const char *csid, struct local_client **new_client);
-int gulm_cluster_send_message(void *buf, int msglen, const char *csid, const char *errtext);
-void get_our_gulm_csid(char *csid);
-int gulm_connect_csid(const char *csid, struct local_client **newclient);
index 8d9a7b9af2b6ab1fbd28076ee7b0b67c01e5cc98..adf7a925a79edd278526af768f76a8a0f0ceacd7 100644 (file)
@@ -121,7 +121,8 @@ static void process_signals(void)
 
 static void remove_lockfile(void)
 {
-       unlink(CMIRRORD_PIDFILE);
+       if (unlink(CMIRRORD_PIDFILE))
+               LOG_ERROR("Unable to remove \"" CMIRRORD_PIDFILE "\" %s", strerror(errno));
 }
 
 /*
@@ -133,6 +134,12 @@ static void daemonize(void)
 {
        int pid;
        int status;
+       int devnull;
+
+       if ((devnull = open("/dev/null", O_RDWR)) == -1) {
+               LOG_ERROR("Can't open /dev/null: %s", strerror(errno));
+               exit(EXIT_FAILURE);
+       }
 
        signal(SIGTERM, &parent_exit_handler);
 
@@ -178,13 +185,22 @@ static void daemonize(void)
        }
 
        setsid();
-       chdir("/");
+       if (chdir("/")) {
+               LOG_ERROR("Failed to chdir /: %s", strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
        umask(0);
 
-       close(0); close(1); close(2);
-       open("/dev/null", O_RDONLY); /* reopen stdin */
-       open("/dev/null", O_WRONLY); /* reopen stdout */
-       open("/dev/null", O_WRONLY); /* reopen stderr */
+       if (close(0) || close(1) || close(2)) {
+               LOG_ERROR("Failed to close terminal FDs");
+               exit(EXIT_FAILURE);
+       }
+
+       if ((dup2(devnull, 0) < 0) || /* reopen stdin */
+           (dup2(devnull, 1) < 0) || /* reopen stdout */
+           (dup2(devnull, 2) < 0))   /* reopen stderr */
+               exit(EXIT_FAILURE);
 
        LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON);
 
index b6c925aa05cd301ec2e9adfda7b68dbf8cb5055f..70c76c3ae3573bf9d93464b803edfd0069830608 100644 (file)
 
 #include <corosync/cpg.h>
 #include <errno.h>
-#include <openais/saAis.h>
-#include <openais/saCkpt.h>
 #include <signal.h>
 #include <unistd.h>
+#if CMIRROR_HAS_CHECKPOINT
+#include <openais/saAis.h>
+#include <openais/saCkpt.h>
+#endif
 
 /* Open AIS error codes */
 #define str_ais_error(x)                                               \
        RQ_TYPE((x) & ~DM_ULOG_RESPONSE)
 
 static uint32_t my_cluster_id = 0xDEAD;
+#if CMIRROR_HAS_CHECKPOINT
 static SaCkptHandleT ckpt_handle = 0;
 static SaCkptCallbacksT callbacks = { 0, 0 };
 static SaVersionT version = { 'B', 1, 1 };
+#endif
 
 #define DEBUGGING_HISTORY 100
-//static char debugging[DEBUGGING_HISTORY][128];
-//static int idx = 0;
 #define LOG_SPRINT(cc, f, arg...) do {                         \
                cc->idx++;                                      \
                cc->idx = cc->idx % DEBUGGING_HISTORY;          \
@@ -77,6 +79,7 @@ static SaVersionT version = { 'B', 1, 1 };
 
 static int log_resp_rec = 0;
 
+#define RECOVERING_REGION_SECTION_SIZE 64
 struct checkpoint_data {
        uint32_t requester;
        char uuid[CPG_MAX_NAME_LENGTH];
@@ -86,7 +89,7 @@ struct checkpoint_data {
        char *clean_bits;
        char *recovering_region;
        struct checkpoint_data *next;
-};     
+};
 
 #define INVALID 0
 #define VALID   1
@@ -128,7 +131,6 @@ static struct dm_list clog_cpg_list;
 int cluster_send(struct clog_request *rq)
 {
        int r;
-       int count=0;
        int found = 0;
        struct iovec iov;
        struct clog_cpg *entry;
@@ -165,7 +167,10 @@ int cluster_send(struct clog_request *rq)
        if (entry->cpg_state != VALID)
                return -EINVAL;
 
+#if CMIRROR_HAS_CHECKPOINT
        do {
+               int count = 0;
+
                r = cpg_mcast_joined(entry->handle, CPG_TYPE_AGREED, &iov, 1);
                if (r != SA_AIS_ERR_TRY_AGAIN)
                        break;
@@ -189,12 +194,14 @@ int cluster_send(struct clog_request *rq)
                                  str_ais_error(r));
                usleep(1000);
        } while (1);
-
-       if (r == CPG_OK)
+#else
+       r = cpg_mcast_joined(entry->handle, CPG_TYPE_AGREED, &iov, 1);
+#endif
+       if (r == CS_OK)
                return 0;
 
        /* error codes found in openais/cpg.h */
-       LOG_ERROR("cpg_mcast_joined error: %s", str_ais_error(r));
+       LOG_ERROR("cpg_mcast_joined error: %d", r);
 
        rq->u_rq.error = -EBADE;
        return -EBADE;
@@ -419,6 +426,7 @@ static void free_checkpoint(struct checkpoint_data *cp)
        free(cp);
 }
 
+#if CMIRROR_HAS_CHECKPOINT
 static int export_checkpoint(struct checkpoint_data *cp)
 {
        SaCkptCheckpointCreationAttributesT attr;
@@ -587,7 +595,54 @@ rr_create_retry:
        return 0;
 }
 
-static int import_checkpoint(struct clog_cpg *entry, int no_read)
+#else
+static int export_checkpoint(struct checkpoint_data *cp)
+{
+       int r, rq_size;
+       struct clog_request *rq;
+
+       rq_size = sizeof(*rq);
+       rq_size += RECOVERING_REGION_SECTION_SIZE;
+       rq_size += cp->bitmap_size * 2; /* clean|sync_bits */
+
+       rq = malloc(rq_size);
+       if (!rq) {
+               LOG_ERROR("export_checkpoint: "
+                         "Unable to allocate transfer structs");
+               return -ENOMEM;
+       }
+       memset(rq, 0, rq_size);
+
+       dm_list_init(&rq->u.list);
+       rq->u_rq.request_type = DM_ULOG_CHECKPOINT_READY;
+       rq->originator = cp->requester;
+       strncpy(rq->u_rq.uuid, cp->uuid, CPG_MAX_NAME_LENGTH);
+       rq->u_rq.seq = my_cluster_id;
+       rq->u_rq.data_size = rq_size - sizeof(*rq);
+
+       /* Sync bits */
+       memcpy(rq->u_rq.data, cp->sync_bits, cp->bitmap_size);
+
+       /* Clean bits */
+       memcpy(rq->u_rq.data + cp->bitmap_size, cp->clean_bits, cp->bitmap_size);
+
+       /* Recovering region */
+       memcpy(rq->u_rq.data + (cp->bitmap_size * 2), cp->recovering_region,
+              strlen(cp->recovering_region));
+
+       r = cluster_send(rq);
+       if (r)
+               LOG_ERROR("Failed to send checkpoint ready notice: %s",
+                         strerror(-r));
+
+       free(rq);
+       return 0;
+}
+#endif /* CMIRROR_HAS_CHECKPOINT */
+
+#if CMIRROR_HAS_CHECKPOINT
+static int import_checkpoint(struct clog_cpg *entry, int no_read,
+                            struct clog_request *rq __attribute__((unused)))
 {
        int rtn = 0;
        SaCkptCheckpointHandleT h;
@@ -619,6 +674,7 @@ open_retry:
        if (rv != SA_AIS_OK) {
                LOG_ERROR("[%s] Failed to open checkpoint: %s",
                          SHORT_UUID(entry->name.value), str_ais_error(rv));
+               free(bitmap);
                return -EIO; /* FIXME: better error */
        }
 
@@ -647,6 +703,7 @@ init_retry:
        if (rv != SA_AIS_OK) {
                LOG_ERROR("[%s] Sync checkpoint section creation failed: %s",
                          SHORT_UUID(entry->name.value), str_ais_error(rv));
+               free(bitmap);
                return -EIO; /* FIXME: better error */
        }
 
@@ -740,6 +797,32 @@ no_read:
        return rtn;
 }
 
+#else
+static int import_checkpoint(struct clog_cpg *entry, int no_read,
+                            struct clog_request *rq)
+{
+       int bitmap_size;
+
+       bitmap_size = (rq->u_rq.data_size - RECOVERING_REGION_SECTION_SIZE) / 2;
+       if (bitmap_size < 0) {
+               LOG_ERROR("Checkpoint has invalid payload size.");
+               return -EINVAL;
+       }
+
+       if (pull_state(entry->name.value, entry->luid, "sync_bits",
+                      rq->u_rq.data, bitmap_size) ||
+           pull_state(entry->name.value, entry->luid, "clean_bits",
+                      rq->u_rq.data + bitmap_size, bitmap_size) ||
+           pull_state(entry->name.value, entry->luid, "recovering_region",
+                      rq->u_rq.data + (bitmap_size * 2),
+                      RECOVERING_REGION_SECTION_SIZE)) {
+               LOG_ERROR("Error loading bitmap state from checkpoint.");
+               return -EIO;
+       }
+       return 0;
+}
+#endif /* CMIRROR_HAS_CHECKPOINT */
+
 static void do_checkpoints(struct clog_cpg *entry, int leaving)
 {
        struct checkpoint_data *cp;
@@ -827,10 +910,11 @@ static int resend_requests(struct clog_cpg *entry)
                                   rq->u_rq.seq);
 
                        rq->u_rq.data_size = 0;
-                       kernel_send(&rq->u_rq);
-                               
+                       if (kernel_send(&rq->u_rq))
+                               LOG_ERROR("Failed to respond to kernel [%s]",
+                                         RQ_TYPE(rq->u_rq.request_type));
                        break;
-                       
+
                default:
                        /*
                         * If an action or a response is required, then
@@ -857,13 +941,13 @@ static int resend_requests(struct clog_cpg *entry)
 
 static int do_cluster_work(void *data __attribute__((unused)))
 {
-       int r = SA_AIS_OK;
+       int r = CS_OK;
        struct clog_cpg *entry, *tmp;
 
        dm_list_iterate_items_safe(entry, tmp, &clog_cpg_list) {
-               r = cpg_dispatch(entry->handle, CPG_DISPATCH_ALL);
-               if (r != SA_AIS_OK)
-                       LOG_ERROR("cpg_dispatch failed: %s", str_ais_error(r));
+               r = cpg_dispatch(entry->handle, CS_DISPATCH_ALL);
+               if (r != CS_OK)
+                       LOG_ERROR("cpg_dispatch failed: %d", r);
 
                if (entry->free_me) {
                        free(entry);
@@ -874,7 +958,7 @@ static int do_cluster_work(void *data __attribute__((unused)))
                resend_requests(entry);
        }
 
-       return (r == SA_AIS_OK) ? 0 : -1;  /* FIXME: good error number? */
+       return (r == CS_OK) ? 0 : -1;  /* FIXME: good error number? */
 }
 
 static int flush_startup_list(struct clog_cpg *entry)
@@ -939,16 +1023,19 @@ static void cpg_message_callback(cpg_handle_t handle, const struct cpg_name *gna
        struct clog_request *tmp_rq;
        struct clog_cpg *match;
 
-       if (clog_request_from_network(rq, msg_len) < 0)
-               /* Error message comes from 'clog_request_from_network' */
-               return;
-
        match = find_clog_cpg(handle);
        if (!match) {
                LOG_ERROR("Unable to find clog_cpg for cluster message");
                return;
        }
 
+       /*
+        * Perform necessary endian and version compatibility conversions
+        */
+       if (clog_request_from_network(rq, msg_len) < 0)
+               /* Any error messages come from 'clog_request_from_network' */
+               return;
+
        if ((nodeid == my_cluster_id) &&
            !(rq->u_rq.request_type & DM_ULOG_RESPONSE) &&
            (rq->u_rq.request_type != DM_ULOG_RESUME) &&
@@ -967,7 +1054,7 @@ static void cpg_message_callback(cpg_handle_t handle, const struct cpg_name *gna
                }
                memcpy(tmp_rq, rq, sizeof(*rq) + rq->u_rq.data_size);
                dm_list_init(&tmp_rq->u.list);
-               dm_list_add( &match->working_list, &tmp_rq->u.list);
+               dm_list_add(&match->working_list, &tmp_rq->u.list);
        }
 
        if (rq->u_rq.request_type == DM_ULOG_POSTSUSPEND) {
@@ -1020,7 +1107,8 @@ static void cpg_message_callback(cpg_handle_t handle, const struct cpg_name *gna
                        /* Redundant checkpoints ignored if match->valid */
                        LOG_SPRINT(match, "[%s] CHECKPOINT_READY notification from %u",
                                   SHORT_UUID(rq->u_rq.uuid), nodeid);
-                       if (import_checkpoint(match, (match->state != INVALID))) {
+                       if (import_checkpoint(match,
+                                             (match->state != INVALID), rq)) {
                                LOG_SPRINT(match,
                                           "[%s] Failed to import checkpoint from %u",
                                           SHORT_UUID(rq->u_rq.uuid), nodeid);
@@ -1144,11 +1232,11 @@ out:
                                   _RQ_TYPE(rq->u_rq.request_type),
                                   rq->originator, (response) ? "YES" : "NO");
                else
-                       LOG_SPRINT(match, "SEQ#=%u, UUID=%s, TYPE=%s, ORIG=%u, RESP=%s, RSPR=%u",
+                       LOG_SPRINT(match, "SEQ#=%u, UUID=%s, TYPE=%s, ORIG=%u, RESP=%s, RSPR=%u, error=%d",
                                   rq->u_rq.seq, SHORT_UUID(rq->u_rq.uuid),
                                   _RQ_TYPE(rq->u_rq.request_type),
                                   rq->originator, (response) ? "YES" : "NO",
-                                  nodeid);
+                                  nodeid, rq->u_rq.error);
        }
 }
 
@@ -1161,7 +1249,7 @@ static void cpg_join_callback(struct clog_cpg *match,
        uint32_t my_pid = (uint32_t)getpid();
        uint32_t lowest = match->lowest_id;
        struct clog_request *rq;
-       char dbuf[32];
+       char dbuf[32] = { 0 };
 
        /* Assign my_cluster_id */
        if ((my_cluster_id == 0xDEAD) && (joined->pid == my_pid))
@@ -1177,7 +1265,6 @@ static void cpg_join_callback(struct clog_cpg *match,
        if (joined->nodeid == my_cluster_id)
                goto out;
 
-       memset(dbuf, 0, sizeof(dbuf));
        for (i = 0; i < member_list_entries - 1; i++)
                sprintf(dbuf+strlen(dbuf), "%u-", member_list[i].nodeid);
        sprintf(dbuf+strlen(dbuf), "(%u)", joined->nodeid);
@@ -1259,7 +1346,9 @@ static void cpg_leave_callback(struct clog_cpg *match,
                        dm_list_del(&rq->u.list);
 
                        if (rq->u_rq.request_type == DM_ULOG_POSTSUSPEND)
-                               kernel_send(&rq->u_rq);
+                               if (kernel_send(&rq->u_rq))
+                                       LOG_ERROR("Failed to respond to kernel [%s]",
+                                                 RQ_TYPE(rq->u_rq.request_type));
                        free(rq);
                }
 
@@ -1268,7 +1357,7 @@ static void cpg_leave_callback(struct clog_cpg *match,
                match->free_me = 1;
                match->lowest_id = 0xDEAD;
                match->state = INVALID;
-       }                       
+       }
 
        /* Remove any pending checkpoints for the leaving node. */
        for (p_cp = NULL, c_cp = match->checkpoint_list;
@@ -1324,7 +1413,7 @@ static void cpg_leave_callback(struct clog_cpg *match,
                         left->nodeid);
                return;
        }
-               
+
        match->lowest_id = member_list[0].nodeid;
        for (i = 0; i < member_list_entries; i++)
                if (match->lowest_id > member_list[i].nodeid)
@@ -1413,6 +1502,7 @@ cpg_callbacks_t cpg_callbacks = {
  */
 static int remove_checkpoint(struct clog_cpg *entry)
 {
+#if CMIRROR_HAS_CHECKPOINT
        int len;
        SaNameT name;
        SaAisErrorT rv;
@@ -1442,7 +1532,7 @@ unlink_retry:
                 usleep(1000);
                 goto unlink_retry;
         }
-       
+
        if (rv != SA_AIS_OK) {
                 LOG_ERROR("[%s] Failed to unlink checkpoint: %s",
                           SHORT_UUID(entry->name.value), str_ais_error(rv));
@@ -1452,6 +1542,10 @@ unlink_retry:
        saCkptCheckpointClose(h);
 
        return 1;
+#else
+       /* No checkpoint to remove, so 'success' */
+       return 1;
+#endif
 }
 
 int create_cluster_cpg(char *uuid, uint64_t luid)
@@ -1493,14 +1587,14 @@ int create_cluster_cpg(char *uuid, uint64_t luid)
                         SHORT_UUID(new->name.value));
 
        r = cpg_initialize(&new->handle, &cpg_callbacks);
-       if (r != SA_AIS_OK) {
+       if (r != CS_OK) {
                LOG_ERROR("cpg_initialize failed:  Cannot join cluster");
                free(new);
                return -EPERM;
        }
 
        r = cpg_join(new->handle, &new->name);
-       if (r != SA_AIS_OK) {
+       if (r != CS_OK) {
                LOG_ERROR("cpg_join failed:  Cannot join cluster");
                free(new);
                return -EPERM;
@@ -1541,7 +1635,7 @@ static int _destroy_cluster_cpg(struct clog_cpg *del)
 {
        int r;
        int state;
-       
+
        LOG_COND(log_resend_requests, "[%s] I am leaving.2.....",
                 SHORT_UUID(del->name.value));
 
@@ -1573,7 +1667,7 @@ static int _destroy_cluster_cpg(struct clog_cpg *del)
                abort_startup(del);
 
        r = cpg_leave(del->handle, &del->name);
-       if (r != CPG_OK)
+       if (r != CS_OK)
                LOG_ERROR("Error leaving CPG!");
        return 0;
 }
@@ -1591,24 +1685,27 @@ int destroy_cluster_cpg(char *uuid)
 
 int init_cluster(void)
 {
+#if CMIRROR_HAS_CHECKPOINT
        SaAisErrorT rv;
 
-       dm_list_init(&clog_cpg_list);
        rv = saCkptInitialize(&ckpt_handle, &callbacks, &version);
 
        if (rv != SA_AIS_OK)
                return EXIT_CLUSTER_CKPT_INIT;
-
+#endif
+       dm_list_init(&clog_cpg_list);
        return 0;
 }
 
 void cleanup_cluster(void)
 {
+#if CMIRROR_HAS_CHECKPOINT
        SaAisErrorT err;
 
        err = saCkptFinalize(ckpt_handle);
        if (err != SA_AIS_OK)
                LOG_ERROR("Failed to finalize checkpoint handle");
+#endif
 }
 
 void cluster_debug(void)
index de807936dff41a45c7cca5f38fd84341973ebd1a..f6e09180dab4623bd27167e38f23c3401f204c7f 100644 (file)
@@ -235,11 +235,9 @@ static int rw_log(struct log_c *lc, int do_write)
  */
 static int read_log(struct log_c *lc)
 {
-       struct log_header lh;
+       struct log_header lh = { 0 };
        size_t bitset_size;
 
-       memset(&lh, 0, sizeof(struct log_header));
-
        if (rw_log(lc, 0))
                return -EIO; /* Failed disk read */
 
@@ -329,19 +327,26 @@ static int find_disk_path(char *major_minor_str, char *path_rtn, int *unlink_pat
                 */
 
                sprintf(path_rtn, "/dev/mapper/%s", dep->d_name);
-               stat(path_rtn, &statbuf);
+               if (stat(path_rtn, &statbuf) < 0) {
+                       LOG_DBG("Unable to stat %s", path_rtn);
+                       continue;
+               }
                if (S_ISBLK(statbuf.st_mode) &&
                    (major(statbuf.st_rdev) == major) &&
                    (minor(statbuf.st_rdev) == minor)) {
                        LOG_DBG("  %s: YES", dep->d_name);
-                       closedir(dp);
+                       if (closedir(dp))
+                               LOG_DBG("Unable to closedir /dev/mapper %s",
+                                       strerror(errno));
                        return 0;
                } else {
                        LOG_DBG("  %s: NO", dep->d_name);
                }
        }
 
-       closedir(dp);
+       if (closedir(dp))
+               LOG_DBG("Unable to closedir /dev/mapper %s",
+                       strerror(errno));
 
        /* FIXME Find out why this was here and deal with underlying problem. */
        LOG_DBG("Path not found for %d/%d", major, minor);
@@ -369,10 +374,10 @@ static int _clog_ctr(char *uuid, uint64_t luid,
        enum sync log_sync = DEFAULTSYNC;
        uint32_t block_on_error = 0;
 
-       int disk_log = 0;
+       int disk_log;
        char disk_path[128];
        int unlink_path = 0;
-       size_t page_size;
+       long page_size;
        int pages;
 
        /* If core log request, then argv[0] will be region_size */
@@ -476,7 +481,12 @@ static int _clog_ctr(char *uuid, uint64_t luid,
        lc->sync_count = (log_sync == NOSYNC) ? region_count : 0;
 
        if (disk_log) {
-               page_size = sysconf(_SC_PAGESIZE);
+               if ((page_size = sysconf(_SC_PAGESIZE)) < 0) {
+                       LOG_ERROR("Unable to read pagesize: %s",
+                                 strerror(errno));
+                       r = errno;
+                       goto fail;
+               }
                pages = *(lc->clean_bits) / page_size;
                pages += *(lc->clean_bits) % page_size ? 1 : 0;
                pages += 1; /* for header */
@@ -489,7 +499,10 @@ static int _clog_ctr(char *uuid, uint64_t luid,
                        goto fail;
                }
                if (unlink_path)
-                       unlink(disk_path);
+                       if (unlink(disk_path) < 0) {
+                               LOG_DBG("Warning: Unable to unlink log device, %s: %s",
+                                       disk_path, strerror(errno));
+                       }
 
                lc->disk_fd = r;
                lc->disk_size = pages * page_size;
@@ -586,7 +599,10 @@ static int clog_ctr(struct dm_ulog_request *rq)
        /* We join the CPG when we resume */
 
        /* No returning data */
-       rq->data_size = 0;
+       if ((rq->version > 1) && !strcmp(argv[0], "clustered-disk"))
+               rq->data_size = sprintf(rq->data, "%s", argv[1]) + 1;
+       else
+               rq->data_size = 0;
 
        if (r) {
                LOG_ERROR("Failed to create cluster log (%s)", rq->uuid);
@@ -626,8 +642,9 @@ static int clog_dtr(struct dm_ulog_request *rq)
        LOG_DBG("[%s] Cluster log removed", SHORT_UUID(lc->uuid));
 
        dm_list_del(&lc->list);
-       if (lc->disk_fd != -1)
-               close(lc->disk_fd);
+       if (lc->disk_fd != -1 && close(lc->disk_fd))
+               LOG_ERROR("Failed to close disk log: %s",
+                         strerror(errno));
        if (lc->disk_buffer)
                free(lc->disk_buffer);
        dm_free(lc->clean_bits);
@@ -770,7 +787,7 @@ static int clog_resume(struct dm_ulog_request *rq)
                else if (lc->disk_nr_regions > lc->region_count)
                        LOG_DBG("[%s] Mirror has shrunk, updating log bits",
                                SHORT_UUID(lc->uuid));
-               break;          
+               break;
        case -EINVAL:
                LOG_DBG("[%s] (Re)initializing mirror log - resync issued.",
                        SHORT_UUID(lc->uuid));
@@ -823,7 +840,7 @@ out:
        lc->sync_search = 0;
        lc->state = LOG_RESUMED;
        lc->recovery_halted = 0;
-       
+
        return rq->error;
 }
 
@@ -1018,7 +1035,7 @@ static int clog_flush(struct dm_ulog_request *rq, int server)
 {
        int r = 0;
        struct log_c *lc = get_log(rq->uuid, rq->luid);
-       
+
        if (!lc)
                return -EINVAL;
 
@@ -1600,7 +1617,7 @@ out:
 
        rq->data_size = sizeof(*pkg);
 
-       return 0;       
+       return 0;
 }
 
 
@@ -1705,14 +1722,12 @@ int do_request(struct clog_request *rq, int server)
 static void print_bits(dm_bitset_t bs, int print)
 {
        int i, size;
-       char outbuf[128];
+       char outbuf[128] = { 0 };
        unsigned char *buf = (unsigned char *)(bs + 1);
 
        size = (*bs % 8) ? 1 : 0;
        size += (*bs / 8);
 
-       memset(outbuf, 0, sizeof(outbuf));
-
        for (i = 0; i < size; i++) {
                if (!(i % 16)) {
                        if (outbuf[0] != '\0') {
@@ -1817,8 +1832,11 @@ int pull_state(const char *uuid, uint64_t luid,
        }
 
        if (!strncmp(which, "recovering_region", 17)) {
-               sscanf(buf, "%llu %u", (unsigned long long *)&lc->recovering_region,
-                      &lc->recoverer);
+               if (sscanf(buf, "%llu %u", (unsigned long long *)&lc->recovering_region,
+                          &lc->recoverer) != 2) {
+                       LOG_ERROR("cannot parse recovering region from: %s", buf);
+                       return -EINVAL;
+               }
                LOG_SPRINT(lc, "CKPT INIT - SEQ#=X, UUID=%s, nodeid = X:: "
                           "recovering_region=%llu, recoverer=%u",
                           SHORT_UUID(lc->uuid),
@@ -1853,7 +1871,7 @@ int pull_state(const char *uuid, uint64_t luid,
 
                LOG_DBG("[%s] loading clean_bits:", SHORT_UUID(lc->uuid));
 
-               print_bits(lc->sync_bits, 0);
+               print_bits(lc->clean_bits, 0);
        }
 
        return 0;
index 80a98d0c91745389bdd1059ed19f83db8d4679d6..74058f99b8fb8bbac8dd197faed5f11c3b3fa4c7 100644 (file)
@@ -58,7 +58,7 @@ int links_register(int fd, const char *name, int (*callback)(void *data), void *
                        free(lc);
                        return -ENOMEM;
                }
-               
+
                pfds = tmp;
                free_pfds = used_pfds + 1;
        }
@@ -125,7 +125,7 @@ int links_monitor(void)
        for (i = 0; i < used_pfds; i++)
                if (pfds[i].revents & POLLIN) {
                        LOG_DBG("Data ready on %d", pfds[i].fd);
-                               
+
                        /* FIXME: Add this back return 1;*/
                        r++;
                }
index 9e076c42ae27d2c46a11d8f52ef7fc9eebc312e0..500f6dced21108b2afd892606d6c1b5f4dd49c35 100644 (file)
@@ -27,7 +27,7 @@
 #define CN_VAL_DM_USERSPACE_LOG         0x1
 #endif
 
-static int cn_fd;  /* Connector (netlink) socket fd */
+static int cn_fd = -1;  /* Connector (netlink) socket fd */
 static char recv_buf[2048];
 static char send_buf[2048];
 
@@ -237,7 +237,6 @@ static int do_local_work(void *data __attribute__((unused)))
        case DM_ULOG_GET_REGION_SIZE:
        case DM_ULOG_IN_SYNC:
        case DM_ULOG_GET_SYNC_COUNT:
-       case DM_ULOG_STATUS_INFO:
        case DM_ULOG_STATUS_TABLE:
        case DM_ULOG_PRESUSPEND:
                /* We do not specify ourselves as server here */
@@ -249,7 +248,7 @@ static int do_local_work(void *data __attribute__((unused)))
                if (r)
                        LOG_ERROR("Failed to respond to kernel [%s]",
                                  RQ_TYPE(u_rq->request_type));
-                       
+
                break;
        case DM_ULOG_RESUME:
                /*
@@ -273,13 +272,16 @@ static int do_local_work(void *data __attribute__((unused)))
        case DM_ULOG_MARK_REGION:
        case DM_ULOG_GET_RESYNC_WORK:
        case DM_ULOG_SET_REGION_SYNC:
+       case DM_ULOG_STATUS_INFO:
        case DM_ULOG_IS_REMOTE_RECOVERING:
        case DM_ULOG_POSTSUSPEND:
                r = cluster_send(rq);
                if (r) {
                        u_rq->data_size = 0;
                        u_rq->error = r;
-                       kernel_send(u_rq);
+                       if (kernel_send(u_rq))
+                               LOG_ERROR("Failed to respond to kernel [%s]",
+                                         RQ_TYPE(u_rq->request_type));
                }
 
                break;
@@ -384,14 +386,18 @@ int init_local(void)
 
        r = bind(cn_fd, (struct sockaddr *) &addr, sizeof(addr));
        if (r < 0) {
-               close(cn_fd);
+               if (close(cn_fd))
+                       LOG_ERROR("Failed to close socket: %s",
+                                 strerror(errno));
                return EXIT_KERNEL_BIND;
        }
 
        opt = addr.nl_groups;
        r = setsockopt(cn_fd, 270, NETLINK_ADD_MEMBERSHIP, &opt, sizeof(opt));
        if (r) {
-               close(cn_fd);
+               if (close(cn_fd))
+                       LOG_ERROR("Failed to close socket: %s",
+                                 strerror(errno));
                return EXIT_KERNEL_SETSOCKOPT;
        }
 
@@ -412,5 +418,7 @@ int init_local(void)
 void cleanup_local(void)
 {
        links_unregister(cn_fd);
-       close(cn_fd);
+       if (cn_fd >= 0 && close(cn_fd))
+               LOG_ERROR("Failed to close socket: %s",
+                         strerror(errno));
 }
index 25690c8d1b7d574a225415e9aa1748f1d60a7040..fab74dc1d6f3dd8e740a3806d8424855bb399df6 100644 (file)
@@ -1,3 +1,4 @@
 init_fifos
 fini_fifos
 daemon_talk
+dm_event_get_version
index e99e089bc296dc7e1ee9c49e5e551c7a56eea17d..1302a440ba2e0bfcb183c4e5b03cd812e94540e9 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2005-2010 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2005-2011 Red Hat, Inc. All rights reserved.
 #
 # This file is part of the device-mapper userspace tools.
 #
@@ -60,11 +60,11 @@ LIBS += -ldevmapper
 LVMLIBS += -ldevmapper-event $(PTHREAD_LIBS)
 
 dmeventd: $(LIB_SHARED) dmeventd.o
-       $(CC) $(CFLAGS) $(LDFLAGS) -L. -o $@ dmeventd.o \
+       $(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -L. -o $@ dmeventd.o \
        $(DL_LIBS) $(LVMLIBS) $(LIBS) -rdynamic
 
 dmeventd.static: $(LIB_STATIC) dmeventd.o $(interfacebuilddir)/libdevmapper.a
-       $(CC) $(CFLAGS) $(LDFLAGS) -static -L. -L$(interfacebuilddir) -o $@ \
+       $(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -static -L. -L$(interfacebuilddir) -o $@ \
        dmeventd.o $(DL_LIBS) $(LVMLIBS) $(LIBS) $(STATIC_LIBS)
 
 ifeq ("@PKGCONFIG@", "yes")
@@ -105,4 +105,4 @@ install: install_include install_lib install_dmeventd
 
 install_device-mapper: install_include install_lib install_dmeventd
 
-DISTCLEAN_TARGETS += libdevmapper-event.pc .exported_symbols_generated
+DISTCLEAN_TARGETS += libdevmapper-event.pc
index 2b454f90330bd0b37ec8b7bab17e55791f6d686d..13148c3a2a23b31624cb7c715b0264070de91435 100644 (file)
 #include <arpa/inet.h>         /* for htonl, ntohl */
 
 #ifdef linux
-#  include <malloc.h>
-
-#  define OOM_ADJ_FILE "/proc/self/oom_adj"
+/*
+ * Kernel version 2.6.36 and higher has
+ * new OOM killer adjustment interface.
+ */
+#  define OOM_ADJ_FILE_OLD "/proc/self/oom_adj"
+#  define OOM_ADJ_FILE "/proc/self/oom_score_adj"
 
 /* From linux/oom.h */
+/* Old interface */
 #  define OOM_DISABLE (-17)
 #  define OOM_ADJUST_MIN (-16)
+/* New interface */
+#  define OOM_SCORE_ADJ_MIN (-1000)
+
+/* Systemd on-demand activation support */
+#  define SD_ACTIVATION_ENV_VAR_NAME "SD_ACTIVATION"
+#  define SD_LISTEN_PID_ENV_VAR_NAME "LISTEN_PID"
+#  define SD_LISTEN_FDS_ENV_VAR_NAME "LISTEN_FDS"
+#  define SD_LISTEN_FDS_START 3
+#  define SD_FD_FIFO_SERVER SD_LISTEN_FDS_START
+#  define SD_FD_FIFO_CLIENT (SD_LISTEN_FDS_START + 1)
 
 #endif
 
@@ -95,9 +109,8 @@ static pthread_mutex_t _global_mutex;
 
 #define THREAD_STACK_SIZE (300*1024)
 
-#define DEBUGLOG(fmt, args...) _debuglog(fmt, ## args)
-
 int dmeventd_debug = 0;
+static int _systemd_activation = 0;
 static int _foreground = 0;
 static int _restart = 0;
 static char **_initial_registrations = 0;
@@ -203,24 +216,6 @@ static DM_LIST_INIT(_timeout_registry);
 static pthread_mutex_t _timeout_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t _timeout_cond = PTHREAD_COND_INITIALIZER;
 
-static void _debuglog(const char *fmt, ...)
-{
-        time_t P;
-        va_list ap;
-        if (!_foreground)
-                return;
-        va_start(ap,fmt);
-
-        time(&P);
-        fprintf(stderr, "dmeventd[%p]: %.15s ", (void *) pthread_self(), ctime(&P)+4 );
-        vfprintf(stderr, fmt, ap);
-       fprintf(stderr, "\n");
-
-        va_end(ap);
-}
-
 /* Allocate/free the status structure for a monitoring thread. */
 static struct thread_status *_alloc_thread_status(struct message_data *data,
                                                  struct dso_data *dso_data)
@@ -407,7 +402,9 @@ static int _fill_device_data(struct thread_status *ts)
        if (!dmt)
                return 0;
 
-       dm_task_set_uuid(dmt, ts->device.uuid);
+       if (!dm_task_set_uuid(dmt, ts->device.uuid))
+               goto fail;
+
        if (!dm_task_run(dmt))
                goto fail;
 
@@ -450,7 +447,7 @@ static int _get_status(struct message_data *message_data)
 {
        struct dm_event_daemon_message *msg = message_data->msg;
        struct thread_status *thread;
-       int i = 0, j = 0;
+       int i, j;
        int ret = -1;
        int count = dm_list_size(&_thread_registry);
        int size = 0, current = 0;
@@ -585,6 +582,7 @@ static void _unregister_for_timeout(struct thread_status *thread)
        pthread_mutex_unlock(&_timeout_mutex);
 }
 
+__attribute__((format(printf, 4, 5)))
 static void _no_intr_log(int level, const char *file, int line,
                        const char *f, ...)
 {
@@ -740,8 +738,10 @@ static void _monitor_unregister(void *arg)
                        return;
                }
        thread->status = DM_THREAD_DONE;
+       pthread_mutex_lock(&_timeout_mutex);
        UNLINK_THREAD(thread);
        LINK(thread, &_thread_registry_unused);
+       pthread_mutex_unlock(&_timeout_mutex);
        _unlock_mutex();
 }
 
@@ -752,7 +752,10 @@ static struct dm_task *_get_device_status(struct thread_status *ts)
        if (!dmt)
                return NULL;
 
-       dm_task_set_uuid(dmt, ts->device.uuid);
+       if (!dm_task_set_uuid(dmt, ts->device.uuid)) {
+               dm_task_destroy(dmt);
+               return NULL;
+       }
 
        if (!dm_task_run(dmt)) {
                dm_task_destroy(dmt);
@@ -996,10 +999,8 @@ static int _register_for_event(struct message_data *message_data)
           almost as good as dead already... */
        if (thread_new->events & DM_EVENT_TIMEOUT) {
                ret = -_register_for_timeout(thread_new);
-               if (ret) {
-                   _unlock_mutex();
-                   goto out;
-               }
+               if (ret)
+                       goto outth;
        }
 
        if (!(thread = _lookup_thread_status(message_data))) {
@@ -1025,6 +1026,7 @@ static int _register_for_event(struct message_data *message_data)
        /* Or event # into events bitfield. */
        thread->events |= message_data->events.field;
 
+    outth:
        _unlock_mutex();
 
       out:
@@ -1076,8 +1078,10 @@ static int _unregister_for_event(struct message_data *message_data)
         * unlink and terminate its monitoring thread.
         */
        if (!thread->events) {
+               pthread_mutex_lock(&_timeout_mutex);
                UNLINK_THREAD(thread);
                LINK(thread, &_thread_registry_unused);
+               pthread_mutex_unlock(&_timeout_mutex);
        }
        _unlock_mutex();
 
@@ -1099,15 +1103,19 @@ static int _registered_device(struct message_data *message_data,
        const char *id = message_data->id;
        const char *dso = thread->dso_data->dso_name;
        const char *dev = thread->device.uuid;
+       int r;
        unsigned events = ((thread->status == DM_THREAD_RUNNING)
                           && (thread->events)) ? thread->events : thread->
            events | DM_EVENT_REGISTRATION_PENDING;
 
        dm_free(msg->data);
 
-       msg->size = dm_asprintf(&(msg->data), fmt, id, dso, dev, events);
+       if ((r = dm_asprintf(&(msg->data), fmt, id, dso, dev, events)) < 0) {
+               msg->size = 0;
+               return -ENOMEM;
+       }
 
-       _unlock_mutex();
+       msg->size = (uint32_t) r;
 
        return 0;
 }
@@ -1140,6 +1148,7 @@ static int _want_registered_device(char *dso_name, char *device_uuid,
 static int _get_registered_dev(struct message_data *message_data, int next)
 {
        struct thread_status *thread, *hit = NULL;
+       int ret = -ENOENT;
 
        _lock_mutex();
 
@@ -1156,16 +1165,12 @@ static int _get_registered_dev(struct message_data *message_data, int next)
         * If we got a registered device and want the next one ->
         * fetch next conforming element off the list.
         */
-       if (hit && !next) {
-               _unlock_mutex();
-               return _registered_device(message_data, hit);
-       }
+       if (hit && !next)
+               goto reg;
 
        if (!hit)
                goto out;
 
-       thread = hit;
-
        while (1) {
                if (dm_list_end(&_thread_registry, &thread->list))
                        goto out;
@@ -1177,13 +1182,13 @@ static int _get_registered_dev(struct message_data *message_data, int next)
                }
        }
 
-       _unlock_mutex();
-       return _registered_device(message_data, hit);
+      reg:
+       ret = _registered_device(message_data, hit);
 
       out:
        _unlock_mutex();
-       
-       return -ENOENT;
+
+       return ret;
 }
 
 static int _get_registered_device(struct message_data *message_data)
@@ -1241,68 +1246,66 @@ static void _init_fifos(struct dm_event_fifos *fifos)
 /* Open fifos used for client communication. */
 static int _open_fifos(struct dm_event_fifos *fifos)
 {
-       int orig_errno;
+       struct stat st;
 
        /* Create client fifo. */
        (void) dm_prepare_selinux_context(fifos->client_path, S_IFIFO);
        if ((mkfifo(fifos->client_path, 0600) == -1) && errno != EEXIST) {
-               syslog(LOG_ERR, "%s: Failed to create client fifo.\n", __func__);
-               orig_errno = errno;
+               syslog(LOG_ERR, "%s: Failed to create client fifo %s: %m.\n",
+                      __func__, fifos->client_path);
                (void) dm_prepare_selinux_context(NULL, 0);
-               stack;
-               return -orig_errno;
+               return 0;
        }
 
        /* Create server fifo. */
        (void) dm_prepare_selinux_context(fifos->server_path, S_IFIFO);
        if ((mkfifo(fifos->server_path, 0600) == -1) && errno != EEXIST) {
-               syslog(LOG_ERR, "%s: Failed to create server fifo.\n", __func__);
-               orig_errno = errno;
+               syslog(LOG_ERR, "%s: Failed to create server fifo %s: %m.\n",
+                      __func__, fifos->server_path);
                (void) dm_prepare_selinux_context(NULL, 0);
-               stack;
-               return -orig_errno;
+               return 0;
        }
 
        (void) dm_prepare_selinux_context(NULL, 0);
 
-       struct stat st;
-
        /* Warn about wrong permissions if applicable */
        if ((!stat(fifos->client_path, &st)) && (st.st_mode & 0777) != 0600)
-               syslog(LOG_WARNING, "Fixing wrong permissions on %s",
+               syslog(LOG_WARNING, "Fixing wrong permissions on %s: %m.\n",
                       fifos->client_path);
 
        if ((!stat(fifos->server_path, &st)) && (st.st_mode & 0777) != 0600)
-               syslog(LOG_WARNING, "Fixing wrong permissions on %s",
+               syslog(LOG_WARNING, "Fixing wrong permissions on %s: %m.\n",
                       fifos->server_path);
 
        /* If they were already there, make sure permissions are ok. */
        if (chmod(fifos->client_path, 0600)) {
-               syslog(LOG_ERR, "Unable to set correct file permissions on %s",
+               syslog(LOG_ERR, "Unable to set correct file permissions on %s: %m.\n",
                       fifos->client_path);
-               return -errno;
+               return 0;
        }
 
        if (chmod(fifos->server_path, 0600)) {
-               syslog(LOG_ERR, "Unable to set correct file permissions on %s",
+               syslog(LOG_ERR, "Unable to set correct file permissions on %s: %m.\n",
                       fifos->server_path);
-               return -errno;
+               return 0;
        }
 
        /* Need to open read+write or we will block or fail */
        if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) {
-               stack;
-               return -errno;
+               syslog(LOG_ERR, "Failed to open fifo server %s: %m.\n",
+                      fifos->server_path);
+               return 0;
        }
 
        /* Need to open read+write for select() to work. */
        if ((fifos->client = open(fifos->client_path, O_RDWR)) < 0) {
-               stack;
-               close(fifos->server);
-               return -errno;
+               syslog(LOG_ERR, "Failed to open fifo client %s: %m", fifos->client_path);
+               if (close(fifos->server))
+                       syslog(LOG_ERR, "Failed to close fifo server %s: %m", fifos->server_path);
+               return 0;
        }
 
-       return 0;
+       return 1;
 }
 
 /*
@@ -1405,7 +1408,7 @@ static int _client_write(struct dm_event_fifos *fifos,
 static int _handle_request(struct dm_event_daemon_message *msg,
                          struct message_data *message_data)
 {
-       static struct {
+       static struct request {
                unsigned int cmd;
                int (*f)(struct message_data *);
        } requests[] = {
@@ -1420,7 +1423,7 @@ static int _handle_request(struct dm_event_daemon_message *msg,
                { DM_EVENT_CMD_GET_STATUS, _get_status},
        }, *req;
 
-       for (req = requests; req < requests + sizeof(requests); req++)
+       for (req = requests; req < requests + sizeof(requests) / sizeof(struct request); req++)
                if (req->cmd == msg->cmd)
                        return req->f(message_data);
 
@@ -1432,17 +1435,16 @@ static int _do_process_request(struct dm_event_daemon_message *msg)
 {
        int ret;
        char *answer;
-       static struct message_data message_data;
+       struct message_data message_data = { .msg =  msg };
 
        /* Parse the message. */
-       memset(&message_data, 0, sizeof(message_data));
-       message_data.msg = msg;
        if (msg->cmd == DM_EVENT_CMD_HELLO || msg->cmd == DM_EVENT_CMD_DIE)  {
                ret = 0;
                answer = msg->data;
                if (answer) {
-                       msg->size = dm_asprintf(&(msg->data), "%s %s", answer,
-                                               msg->cmd == DM_EVENT_CMD_DIE ? "DYING" : "HELLO");
+                       msg->size = dm_asprintf(&(msg->data), "%s %s %d", answer,
+                                               msg->cmd == DM_EVENT_CMD_DIE ? "DYING" : "HELLO",
+                                                DM_EVENT_PROTOCOL_VERSION);
                        dm_free(answer);
                } else {
                        msg->size = 0;
@@ -1467,9 +1469,7 @@ static int _do_process_request(struct dm_event_daemon_message *msg)
 static void _process_request(struct dm_event_fifos *fifos)
 {
        int die = 0;
-       struct dm_event_daemon_message msg;
-
-       memset(&msg, 0, sizeof(msg));
+       struct dm_event_daemon_message msg = { 0 };
 
        /*
         * Read the request from the client (client_read, client_write
@@ -1488,9 +1488,9 @@ static void _process_request(struct dm_event_fifos *fifos)
        if (!_client_write(fifos, &msg))
                stack;
 
-       if (die) raise(9);
-
        dm_free(msg.data);
+
+       if (die) raise(9);
 }
 
 static void _process_initial_registrations(void)
@@ -1501,9 +1501,10 @@ static void _process_initial_registrations(void)
 
        while ((reg = _initial_registrations[i])) {
                msg.cmd = DM_EVENT_CMD_REGISTER_FOR_EVENT;
-               msg.size = strlen(reg);
-               msg.data = reg;
-               _do_process_request(&msg);
+               if ((msg.size = strlen(reg))) {
+                       msg.data = reg;
+                       _do_process_request(&msg);
+               }
                ++ i;
        }
 }
@@ -1513,6 +1514,7 @@ static void _cleanup_unused_threads(void)
        int ret;
        struct dm_list *l;
        struct thread_status *thread;
+       int join_ret = 0;
 
        _lock_mutex();
        while ((l = dm_list_first(&_thread_registry_unused))) {
@@ -1552,12 +1554,15 @@ static void _cleanup_unused_threads(void)
 
                if (thread->status == DM_THREAD_DONE) {
                        dm_list_del(l);
-                       pthread_join(thread->thread, NULL);
+                       join_ret = pthread_join(thread->thread, NULL);
                        _free_thread_status(thread);
                }
        }
 
        _unlock_mutex();
+
+       if (join_ret)
+               syslog(LOG_ERR, "Failed pthread_join: %s\n", strerror(join_ret));
 }
 
 static void _sig_alarm(int signum __attribute__((unused)))
@@ -1569,10 +1574,8 @@ static void _sig_alarm(int signum __attribute__((unused)))
 static void _init_thread_signals(void)
 {
        sigset_t my_sigset;
-       struct sigaction act;
+       struct sigaction act = { .sa_handler = _sig_alarm };
 
-       memset(&act, 0, sizeof(act));
-       act.sa_handler = _sig_alarm;
        sigaction(SIGALRM, &act, NULL);
        sigfillset(&my_sigset);
 
@@ -1610,40 +1613,138 @@ static void _exit_handler(int sig __attribute__((unused)))
 }
 
 #ifdef linux
+static int _set_oom_adj(const char *oom_adj_path, int val)
+{
+       FILE *fp;
+
+       if (!(fp = fopen(oom_adj_path, "w"))) {
+               perror("oom_adj: fopen failed");
+               return 0;
+       }
+
+       fprintf(fp, "%i", val);
+
+       if (dm_fclose(fp))
+               perror("oom_adj: fclose failed");
+
+       return 1;
+}
+
 /*
  * Protection against OOM killer if kernel supports it
  */
-static int _set_oom_adj(int val)
+static int _protect_against_oom_killer(void)
 {
-       FILE *fp;
-
        struct stat st;
 
        if (stat(OOM_ADJ_FILE, &st) == -1) {
-               if (errno == ENOENT)
-                       DEBUGLOG(OOM_ADJ_FILE " not found");
-               else
+               if (errno != ENOENT)
                        perror(OOM_ADJ_FILE ": stat failed");
-               return 1;
+
+               /* Try old oom_adj interface as a fallback */
+               if (stat(OOM_ADJ_FILE_OLD, &st) == -1) {
+                       if (errno == ENOENT)
+                               perror(OOM_ADJ_FILE_OLD " not found");
+                       else
+                               perror(OOM_ADJ_FILE_OLD ": stat failed");
+                       return 1;
+               }
+
+               return _set_oom_adj(OOM_ADJ_FILE_OLD, OOM_DISABLE) ||
+                      _set_oom_adj(OOM_ADJ_FILE_OLD, OOM_ADJUST_MIN);
        }
 
-       if (!(fp = fopen(OOM_ADJ_FILE, "w"))) {
-               perror(OOM_ADJ_FILE ": fopen failed");
+       return _set_oom_adj(OOM_ADJ_FILE, OOM_SCORE_ADJ_MIN);
+}
+
+static int _handle_preloaded_fifo(int fd, const char *path)
+{
+       struct stat st_fd, st_path;
+       int flags;
+
+       if ((flags = fcntl(fd, F_GETFD)) < 0)
                return 0;
-       }
 
-       fprintf(fp, "%i", val);
-       if (dm_fclose(fp))
-               perror(OOM_ADJ_FILE ": fclose failed");
+       if (flags & FD_CLOEXEC)
+               return 0;
+
+       if (fstat(fd, &st_fd) < 0 || !S_ISFIFO(st_fd.st_mode))
+               return 0;
+
+       if (stat(path, &st_path) < 0 ||
+           st_path.st_dev != st_fd.st_dev ||
+           st_path.st_ino != st_fd.st_ino)
+               return 0;
+
+       if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
+               return 0;
 
        return 1;
 }
+
+static int _systemd_handover(struct dm_event_fifos *fifos)
+{
+       const char *e;
+       char *p;
+       unsigned long env_pid, env_listen_fds;
+       int r = 0;
+
+       memset(fifos, 0, sizeof(*fifos));
+
+       /* SD_ACTIVATION must be set! */
+       if (!(e = getenv(SD_ACTIVATION_ENV_VAR_NAME)) || strcmp(e, "1"))
+               goto out;
+
+       /* LISTEN_PID must be equal to our PID! */
+       if (!(e = getenv(SD_LISTEN_PID_ENV_VAR_NAME)))
+               goto out;
+
+       errno = 0;
+       env_pid = strtoul(e, &p, 10);
+       if (errno || !p || *p || env_pid <= 0 ||
+           getpid() != (pid_t) env_pid)
+               goto out;
+
+       /* LISTEN_FDS must be 2 and the fds must be FIFOSs! */
+       if (!(e = getenv(SD_LISTEN_FDS_ENV_VAR_NAME)))
+               goto out;
+
+       errno = 0;
+       env_listen_fds = strtoul(e, &p, 10);
+       if (errno || !p || *p || env_listen_fds != 2)
+               goto out;
+
+       /* Check and handle the FIFOs passed in */
+       r = (_handle_preloaded_fifo(SD_FD_FIFO_SERVER, DM_EVENT_FIFO_SERVER) &&
+            _handle_preloaded_fifo(SD_FD_FIFO_CLIENT, DM_EVENT_FIFO_CLIENT));
+
+       if (r) {
+               fifos->server = SD_FD_FIFO_SERVER;
+               fifos->server_path = DM_EVENT_FIFO_SERVER;
+               fifos->client = SD_FD_FIFO_CLIENT;
+               fifos->client_path = DM_EVENT_FIFO_CLIENT;
+       }
+
+out:
+       unsetenv(SD_ACTIVATION_ENV_VAR_NAME);
+       unsetenv(SD_LISTEN_PID_ENV_VAR_NAME);
+       unsetenv(SD_LISTEN_FDS_ENV_VAR_NAME);
+       return r;
+}
 #endif
 
-static void remove_lockfile(void)
+static void _remove_files_on_exit(void)
 {
        if (unlink(DMEVENTD_PIDFILE))
                perror(DMEVENTD_PIDFILE ": unlink failed");
+
+       if (!_systemd_activation) {
+               if (unlink(DM_EVENT_FIFO_CLIENT))
+                       perror(DM_EVENT_FIFO_CLIENT " : unlink failed");
+
+               if (unlink(DM_EVENT_FIFO_SERVER))
+                       perror(DM_EVENT_FIFO_SERVER " : unlink failed");
+       }
 }
 
 static void _daemonize(void)
@@ -1703,8 +1804,15 @@ static void _daemonize(void)
        else
                fd = rlim.rlim_cur;
 
-       for (--fd; fd >= 0; fd--)
-               close(fd);
+       for (--fd; fd >= 0; fd--) {
+#ifdef linux
+               /* Do not close fds preloaded by systemd! */
+               if (_systemd_activation &&
+                   (fd == SD_FD_FIFO_SERVER || fd == SD_FD_FIFO_CLIENT))
+                       continue;
+#endif
+               (void) close(fd);
+       }
 
        if ((open("/dev/null", O_RDONLY) < 0) ||
            (open("/dev/null", O_WRONLY) < 0) ||
@@ -1721,16 +1829,25 @@ static void restart(void)
        int i, count = 0;
        char *message;
        int length;
+       int version;
 
        /* Get the list of registrations from the running daemon. */
 
        if (!init_fifos(&fifos)) {
-               fprintf(stderr, "Could not initiate communication with existing dmeventd.\n");
+               fprintf(stderr, "WARNING: Could not initiate communication with existing dmeventd.\n");
+               exit(EXIT_FAILURE);
+       }
+
+       if (!dm_event_get_version(&fifos, &version)) {
+               fprintf(stderr, "WARNING: Could not communicate with existing dmeventd.\n");
+               fini_fifos(&fifos);
                exit(EXIT_FAILURE);
        }
 
-       if (daemon_talk(&fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0)) {
-               fprintf(stderr, "Could not communicate with existing dmeventd.\n");
+       if (version < 1) {
+               fprintf(stderr, "WARNING: The running dmeventd instance is too old.\n"
+                               "Protocol version %d (required: 1). Action cancelled.\n",
+                               version);
                exit(EXIT_FAILURE);
        }
 
@@ -1749,9 +1866,16 @@ static void restart(void)
                }
        }
 
-       _initial_registrations = dm_malloc(sizeof(char*) * (count + 1));
+       if (!(_initial_registrations = dm_malloc(sizeof(char*) * (count + 1)))) {
+               fprintf(stderr, "Memory allocation registration failed.\n");
+               exit(EXIT_FAILURE);
+       }
+
        for (i = 0; i < count; ++i) {
-               _initial_registrations[i] = dm_strdup(message);
+               if (!(_initial_registrations[i] = dm_strdup(message))) {
+                       fprintf(stderr, "Memory allocation for message failed.\n");
+                       exit(EXIT_FAILURE);
+               }
                message += strlen(message) + 1;
        }
        _initial_registrations[count] = 0;
@@ -1761,17 +1885,28 @@ static void restart(void)
                exit(EXIT_FAILURE);
        }
 
+       /*
+        * Wait for daemon to die, detected by sending further DIE messages
+        * until one fails.
+        */
+       for (i = 0; i < 10; ++i) {
+               if (daemon_talk(&fifos, &msg, DM_EVENT_CMD_DIE, "-", "-", 0, 0))
+                       break; /* yep, it's dead probably */
+               usleep(10);
+       }
+
        fini_fifos(&fifos);
 }
 
 static void usage(char *prog, FILE *file)
 {
        fprintf(file, "Usage:\n"
-               "%s [-V] [-h] [-d] [-d] [-d] [-f]\n\n"
-               "   -V       Show version of dmeventd\n"
-               "   -h       Show this help information\n"
+               "%s [-d [-d [-d]]] [-f] [-h] [-R] [-V] [-?]\n\n"
                "   -d       Log debug messages to syslog (-d, -dd, -ddd)\n"
-               "   -f       Don't fork, run in the foreground\n\n", prog);
+               "   -f       Don't fork, run in the foreground\n"
+               "   -h -?    Show this help information\n"
+               "   -R       Restart dmeventd\n"
+               "   -V       Show version of dmeventd\n\n", prog);
 }
 
 int main(int argc, char *argv[])
@@ -1803,7 +1938,6 @@ int main(int argc, char *argv[])
                case 'V':
                        printf("dmeventd version: %s\n", DM_LIB_VERSION);
                        exit(1);
-                       break;
                }
        }
 
@@ -1818,6 +1952,10 @@ int main(int argc, char *argv[])
        if (_restart)
                restart();
 
+#ifdef linux
+       _systemd_activation = _systemd_handover(&fifos);
+#endif
+
        if (!_foreground)
                _daemonize();
 
@@ -1827,17 +1965,19 @@ int main(int argc, char *argv[])
        if (dm_create_lockfile(DMEVENTD_PIDFILE) == 0)
                exit(EXIT_FAILURE);
 
-       atexit(remove_lockfile);
+       atexit(_remove_files_on_exit);
        (void) dm_prepare_selinux_context(NULL, 0);
 
        /* Set the rest of the signals to cause '_exit_now' to be set */
+       signal(SIGTERM, &_exit_handler);
        signal(SIGINT, &_exit_handler);
        signal(SIGHUP, &_exit_handler);
        signal(SIGQUIT, &_exit_handler);
 
 #ifdef linux
-       if (!_set_oom_adj(OOM_DISABLE) && !_set_oom_adj(OOM_ADJUST_MIN))
-               syslog(LOG_ERR, "Failed to set oom_adj to protect against OOM killer");
+       /* Systemd has adjusted oom killer for us already */
+       if (!_systemd_activation && !_protect_against_oom_killer())
+               syslog(LOG_ERR, "Failed to protect against OOM killer");
 #endif
 
        _init_thread_signals();
@@ -1847,11 +1987,12 @@ int main(int argc, char *argv[])
        //multilog_init_verbose(std_syslog, _LOG_DEBUG);
        //multilog_async(1);
 
-       _init_fifos(&fifos);
+       if (!_systemd_activation)
+               _init_fifos(&fifos);
 
        pthread_mutex_init(&_global_mutex, NULL);
 
-       if (_open_fifos(&fifos))
+       if (!_systemd_activation && !_open_fifos(&fifos))
                exit(EXIT_FIFO_FAILURE);
 
        /* Signal parent, letting them know we are ready to go. */
@@ -1865,11 +2006,13 @@ int main(int argc, char *argv[])
        while (!_exit_now) {
                _process_request(&fifos);
                _cleanup_unused_threads();
+               _lock_mutex();
                if (!dm_list_empty(&_thread_registry)
                    || !dm_list_empty(&_thread_registry_unused))
                        _thread_registries_empty = 0;
                else
                        _thread_registries_empty = 1;
+               _unlock_mutex();
        }
 
        _exit_dm_lib();
index 254758e16fb5e4950f8e91a6edfdbd7e58f1e3d1..e21cf45de8528e09fd8a7b6f0a9b5f1a70435c7d 100644 (file)
 
 /* FIXME This stuff must be configurable. */
 
-#define        DM_EVENT_DAEMON         "/sbin/dmeventd"
-#define DM_EVENT_LOCKFILE      "/var/lock/dmeventd"
-#define        DM_EVENT_FIFO_CLIENT    "/var/run/dmeventd-client"
-#define        DM_EVENT_FIFO_SERVER    "/var/run/dmeventd-server"
-#define DM_EVENT_PIDFILE       "/var/run/dmeventd.pid"
+#define        DM_EVENT_FIFO_CLIENT    DEFAULT_DM_RUN_DIR "/dmeventd-client"
+#define        DM_EVENT_FIFO_SERVER    DEFAULT_DM_RUN_DIR "/dmeventd-server"
 
 #define DM_EVENT_DEFAULT_TIMEOUT 10
 
@@ -66,11 +63,13 @@ struct dm_event_fifos {
 #define EXIT_CHDIR_FAILURE       7
 
 /* Implemented in libdevmapper-event.c, but not part of public API. */
+// FIXME  misuse of bitmask as enum
 int daemon_talk(struct dm_event_fifos *fifos,
                struct dm_event_daemon_message *msg, int cmd,
                const char *dso_name, const char *dev_name,
                enum dm_event_mask evmask, uint32_t timeout);
 int init_fifos(struct dm_event_fifos *fifos);
 void fini_fifos(struct dm_event_fifos *fifos);
+int dm_event_get_version(struct dm_event_fifos *fifos, int *version);
 
 #endif /* __DMEVENTD_DOT_H__ */
index bc8ad993dd718cef80d17f3cd211ce967a933435..1f8fbef544bdb87a2431955758350b05f998bbdc 100644 (file)
@@ -59,14 +59,10 @@ struct dm_event_handler *dm_event_handler_create(void)
 {
        struct dm_event_handler *dmevh = NULL;
 
-       if (!(dmevh = dm_malloc(sizeof(*dmevh))))
+       if (!(dmevh = dm_zalloc(sizeof(*dmevh)))) {
+               log_error("Failed to allocate event handler.");
                return NULL;
-
-       dmevh->dmeventd_path = NULL;
-       dmevh->dso = dmevh->dev_name = dmevh->uuid = NULL;
-       dmevh->major = dmevh->minor = 0;
-       dmevh->mask = 0;
-       dmevh->timeout = 0;
+       }
 
        return dmevh;
 }
@@ -245,6 +241,10 @@ static int _daemon_read(struct dm_event_fifos *fifos,
                                log_error("Unable to read from event server");
                                return 0;
                        }
+                       if ((ret == 0) && (i > 4) && !bytes) {
+                               log_error("No input from event server.");
+                               return 0;
+                       }
                }
                if (ret < 1) {
                        log_error("Unable to read from event server.");
@@ -309,7 +309,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
                }
                if (ret == 0)
                        break;
-               read(fifos->server, drainbuf, 127);
+               ret = read(fifos->server, drainbuf, 127);
        }
 
        while (bytes < size) {
@@ -424,30 +424,27 @@ static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
        fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK);
        if (fifos->client >= 0) {
                /* server is running and listening */
-
-               close(fifos->client);
+               if (close(fifos->client))
+                       log_sys_error("close", fifos->client_path);
                return 1;
        } else if (errno != ENXIO) {
                /* problem */
-
-               log_error("%s: Can't open client fifo %s: %s",
-                         __func__, fifos->client_path, strerror(errno));
-               stack;
+               log_sys_error("open", fifos->client_path);
                return 0;
        }
 
       start_server:
        /* server is not running */
 
-       if (!strncmp(DMEVENTD_PATH, "/", 1) && stat(DMEVENTD_PATH, &statbuf)) {
-               log_error("Unable to find dmeventd.");
-               return_0;
+       if ((args[0][0] == '/') && stat(args[0], &statbuf)) {
+               log_sys_error("stat", args[0]);
+               return 0;
        }
 
        pid = fork();
 
        if (pid < 0)
-               log_error("Unable to fork.");
+               log_sys_error("fork", "");
 
        else if (!pid) {
                execvp(args[0], args);
@@ -477,25 +474,23 @@ int init_fifos(struct dm_event_fifos *fifos)
 
        /* Open the fifo used to read from the daemon. */
        if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) {
-               log_error("%s: open server fifo %s",
-                         __func__, fifos->server_path);
-               stack;
+               log_sys_error("open", fifos->server_path);
                return 0;
        }
 
        /* Lock out anyone else trying to do communication with the daemon. */
        if (flock(fifos->server, LOCK_EX) < 0) {
-               log_error("%s: flock %s", __func__, fifos->server_path);
-               close(fifos->server);
+               log_sys_error("flock", fifos->server_path);
+               if (close(fifos->server))
+                       log_sys_error("close", fifos->server_path);
                return 0;
        }
 
 /*     if ((fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK)) < 0) {*/
        if ((fifos->client = open(fifos->client_path, O_RDWR | O_NONBLOCK)) < 0) {
-               log_error("%s: Can't open client fifo %s: %s",
-                         __func__, fifos->client_path, strerror(errno));
-               close(fifos->server);
-               stack;
+               log_sys_error("open", fifos->client_path);
+               if (close(fifos->server))
+                       log_sys_error("close", fifos->server_path);
                return 0;
        }
 
@@ -523,8 +518,10 @@ void fini_fifos(struct dm_event_fifos *fifos)
        if (flock(fifos->server, LOCK_UN))
                log_error("flock unlock %s", fifos->server_path);
 
-       close(fifos->client);
-       close(fifos->server);
+       if (close(fifos->client))
+               log_sys_error("close", fifos->client_path);
+       if (close(fifos->server))
+               log_sys_error("close", fifos->server_path);
 }
 
 /* Get uuid of a device */
@@ -538,34 +535,46 @@ static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
                return NULL;
        }
 
-       if (dmevh->uuid)
-               dm_task_set_uuid(dmt, dmevh->uuid);
-       else if (dmevh->dev_name)
-               dm_task_set_name(dmt, dmevh->dev_name);
-       else if (dmevh->major && dmevh->minor) {
-               dm_task_set_major(dmt, dmevh->major);
-               dm_task_set_minor(dmt, dmevh->minor);
-        }
+       if (dmevh->uuid) {
+               if (!dm_task_set_uuid(dmt, dmevh->uuid))
+                       goto_bad;
+       } else if (dmevh->dev_name) {
+               if (!dm_task_set_name(dmt, dmevh->dev_name))
+                       goto_bad;
+       } else if (dmevh->major && dmevh->minor) {
+               if (!dm_task_set_major(dmt, dmevh->major) ||
+                   !dm_task_set_minor(dmt, dmevh->minor))
+                       goto_bad;
+       }
 
        /* FIXME Add name or uuid or devno to messages */
        if (!dm_task_run(dmt)) {
                log_error("_get_device_info: dm_task_run() failed");
-               goto failed;
+               goto bad;
        }
 
        if (!dm_task_get_info(dmt, &info)) {
                log_error("_get_device_info: failed to get info for device");
-               goto failed;
+               goto bad;
        }
 
        if (!info.exists) {
-               log_error("_get_device_info: device not found");
-               goto failed;
+               log_error("_get_device_info: %s%s%s%.0d%s%.0d%s%s: device not found",
+                         dmevh->uuid ? : "", 
+                         (!dmevh->uuid && dmevh->dev_name) ? dmevh->dev_name : "", 
+                         (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? "(" : "",
+                         (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? dmevh->major : 0,
+                         (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? ":" : "",
+                         (!dmevh->uuid && !dmevh->dev_name && dmevh->minor > 0) ? dmevh->minor : 0,
+                         (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) && dmevh->minor == 0 ? "0" : "",
+                         (!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? ") " : "");
+               goto bad;
        }
 
+                 
        return dmt;
 
-failed:
+      bad:
        dm_task_destroy(dmt);
        return NULL;
 }
@@ -715,17 +724,18 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
 
        uuid = dm_task_get_uuid(dmt);
 
-       if (!(ret = _do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
-                            DM_EVENT_CMD_GET_REGISTERED_DEVICE, dmevh->dmeventd_path,
-                             &msg, dmevh->dso, uuid, dmevh->mask, 0))) {
-               /* FIXME this will probably horribly break if we get
-                  ill-formatted reply */
-               ret = _parse_message(&msg, &reply_dso, &reply_uuid, &reply_mask);
-       } else {
+       if (_do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
+                     DM_EVENT_CMD_GET_REGISTERED_DEVICE, dmevh->dmeventd_path,
+                     &msg, dmevh->dso, uuid, dmevh->mask, 0)) {
+               log_debug("%s: device not registered.", dm_task_get_name(dmt));
                ret = -ENOENT;
                goto fail;
        }
 
+       /* FIXME this will probably horribly break if we get
+          ill-formatted reply */
+       ret = _parse_message(&msg, &reply_dso, &reply_uuid, &reply_mask);
+
        dm_task_destroy(dmt);
        dmt = NULL;
 
@@ -733,6 +743,10 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
        msg.data = NULL;
 
        _dm_event_handler_clear_dev_info(dmevh);
+       if (!reply_uuid) {
+               ret = -ENXIO; /* dmeventd probably gave us bogus uuid back */
+               goto fail;
+       }
        dmevh->uuid = dm_strdup(reply_uuid);
        if (!dmevh->uuid) {
                ret = -ENOMEM;
@@ -781,6 +795,36 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
        return ret;
 }
 
+/*
+ * You can (and have to) call this at the stage of the protocol where
+ *     daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0)
+ *
+ * would be normally sent. This call will parse the version reply from
+ * dmeventd, in addition to above call. It is not safe to call this at any
+ * other place in the protocol.
+ *
+ * This is an internal function, not exposed in the public API.
+ */
+
+int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
+       char *p;
+       struct dm_event_daemon_message msg = { 0, 0, NULL };
+
+       if (daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0))
+               return 0;
+       p = msg.data;
+       *version = 0;
+
+       p = strchr(p, ' '); /* Message ID */
+        if (!p) return 0;
+       p = strchr(p + 1, ' '); /* HELLO */
+        if (!p) return 0;
+       p = strchr(p + 1, ' '); /* HELLO, once more */
+       if (p)
+               *version = atoi(p);
+       return 1;
+}
+
 #if 0                          /* left out for now */
 
 static char *_skip_string(char *src, const int delimiter)
index 0de20c145ffd8751269f36fc892ef21bf857b7b1..7ce3f397dee9346849843dc64dd2d801858a7f0c 100644 (file)
@@ -46,6 +46,7 @@ enum dm_event_mask {
 };
 
 #define DM_EVENT_ALL_ERRORS DM_EVENT_ERROR_MASK
+#define DM_EVENT_PROTOCOL_VERSION 1
 
 struct dm_event_handler;
 
@@ -81,6 +82,7 @@ void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout);
 /*
  * Specify mask for events to monitor.
  */
+// FIXME  misuse of bitmask as enum
 void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh,
                                     enum dm_event_mask evmask);
 
@@ -90,6 +92,7 @@ const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh);
 int dm_event_handler_get_major(const struct dm_event_handler *dmevh);
 int dm_event_handler_get_minor(const struct dm_event_handler *dmevh);
 int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh);
+// FIXME  misuse of bitmask as enum
 enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh);
 
 /* FIXME Review interface (what about this next thing?) */
@@ -103,6 +106,7 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh);
 
 /* Prototypes for DSO interface, see dmeventd.c, struct dso_data for
    detailed descriptions. */
+// FIXME  misuse of bitmask as enum
 void process_event(struct dm_task *dmt, enum dm_event_mask evmask, void **user);
 int register_device(const char *device_name, const char *uuid, int major, int minor, void **user);
 int unregister_device(const char *device_name, const char *uuid, int major,
index 45176ad7f33fa8989792dcc626d0712208202081..b26e6d8277ea467095c63f58a4648a5b70cfe212 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
-# Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2004-2005, 2011 Red Hat, Inc. All rights reserved.
 #
 # This file is part of LVM2.
 #
@@ -16,10 +16,31 @@ srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 top_builddir = @top_builddir@
 
-SUBDIRS += lvm2 mirror snapshot
+SUBDIRS += lvm2
+
+ifneq ("@MIRRORS@", "none")
+  SUBDIRS += mirror
+endif
+
+ifneq ("@SNAPSHOTS@", "none")
+  SUBDIRS += snapshot
+endif
+
+ifneq ("@RAID@", "none")
+  SUBDIRS += raid
+endif
+
+ifneq ("@THIN@", "none")
+  SUBDIRS += thin
+endif
+
+ifeq ($(MAKECMDGOALS),distclean)
+  SUBDIRS = lvm2 mirror snapshot raid thin
+endif
 
 include $(top_builddir)/make.tmpl
 
-mirror: lvm2
 snapshot: lvm2
-
+mirror: lvm2
+raid: lvm2
+thin: lvm2
index ebe3d0573d8181c55036991a28ee1522fc33ab23..646e4cf304448d260d8479e175a044a3e41ef606 100644 (file)
@@ -4,3 +4,4 @@ dmeventd_lvm2_lock
 dmeventd_lvm2_unlock
 dmeventd_lvm2_pool
 dmeventd_lvm2_run
+dmeventd_lvm2_command
index 46247aabc35c2eda82f4e100592126be806fc9ec..fcb2a0a8c514e736e61ee56f87c490e26bd85404 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2010-2011 Red Hat, Inc. All rights reserved.
 #
 # This file is part of LVM2.
 #
@@ -24,10 +24,8 @@ LIB_VERSION = $(LIB_VERSION_LVM)
 
 include $(top_builddir)/make.tmpl
 
-LIBS += @LVM2CMD_LIB@ -ldevmapper $(PTHREAD_LIBS)
+LIBS += @LVM2CMD_LIB@ -ldevmapper $(PTHREAD_LIBS) $(DAEMON_LIBS)
 
 install_lvm2: install_lib_shared
 
 install: install_lvm2
-
-DISTCLEAN_TARGETS += .exported_symbols_generated
index 937d81d9feab1c047dabb1bfa6362d4b33ddee90..5d5a46b802ca1ef88fee4d7a35276c660f2fc3c9 100644 (file)
@@ -16,8 +16,6 @@
 #include "log.h"
 
 #include "lvm2cmd.h"
-#include "errors.h"
-#include "libdevmapper-event.h"
 #include "dmeventd_lvm.h"
 
 #include <pthread.h>
@@ -82,10 +80,7 @@ static void _temporary_log_fn(int level,
 
 void dmeventd_lvm2_lock(void)
 {
-       if (pthread_mutex_trylock(&_event_mutex)) {
-               syslog(LOG_NOTICE, "Another thread is handling an event. Waiting...");
-               pthread_mutex_lock(&_event_mutex);
-       }
+       pthread_mutex_lock(&_event_mutex);
 }
 
 void dmeventd_lvm2_unlock(void)
@@ -113,6 +108,7 @@ int dmeventd_lvm2_init(void)
                        _mem_pool = NULL;
                        goto out;
                }
+               lvm2_disable_dmeventd_monitoring(_lvm_handle);
                /* FIXME Temporary: move to dmeventd core */
                lvm2_run(_lvm_handle, "_memlock_inc");
        }
@@ -150,3 +146,31 @@ int dmeventd_lvm2_run(const char *cmdline)
        return lvm2_run(_lvm_handle, cmdline);
 }
 
+int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
+                         const char *cmd, const char *device)
+{
+       char *vg = NULL, *lv = NULL, *layer;
+       int r;
+
+       if (!dm_split_lvm_name(mem, device, &vg, &lv, &layer)) {
+               syslog(LOG_ERR, "Unable to determine VG name from %s.\n",
+                      device);
+               return 0;
+       }
+
+       /* strip off the mirror component designations */
+       layer = strstr(lv, "_mlog");
+       if (layer)
+               *layer = '\0';
+
+       r = dm_snprintf(buffer, size, "%s %s/%s", cmd, vg, lv);
+
+       dm_pool_free(mem, vg);
+
+       if (r < 0) {
+               syslog(LOG_ERR, "Unable to form LVM command. (too long).\n");
+               return 0;
+       }
+
+       return 1;
+}
index 8efcb9b647cf627367d2d7eccd1cdaa9a53fe9a8..1960c71964d0721099457e5009cdb8388d0abc41 100644 (file)
@@ -36,4 +36,7 @@ void dmeventd_lvm2_unlock(void);
 
 struct dm_pool *dmeventd_lvm2_pool(void);
 
+int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
+                         const char *cmd, const char *device);
+
 #endif /* _DMEVENTD_LVMWRAP_H */
index 7f80629d34bf03586d226ce2a770ce8a87c4c5ed..85b33c93b40b901415621c73eb5b3acf3d361a21 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
-# Copyright (C) 2004-2005, 2008-2010 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2004-2005, 2008-2011 Red Hat, Inc. All rights reserved.
 #
 # This file is part of LVM2.
 #
@@ -30,10 +30,8 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
 
 include $(top_builddir)/make.tmpl
 
-LIBS += -ldevmapper-event-lvm2 -ldevmapper
+LIBS += -ldevmapper-event-lvm2 -ldevmapper $(DAEMON_LIBS)
 
 install_lvm2: install_dm_plugin
 
 install: install_lvm2
-
-DISTCLEAN_TARGETS += .exported_symbols_generated
index 3e97d87302f54df17a26cc3a917d4f34f019099a..e59feb4882b46a614f5535b0efad04e0b87f5dda 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005-2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2005-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -18,6 +18,7 @@
 #include "errors.h"
 #include "libdevmapper-event.h"
 #include "dmeventd_lvm.h"
+#include "defaults.h"
 
 #include <syslog.h> /* FIXME Replace syslog with multilog */
 /* FIXME Missing openlog? */
@@ -81,7 +82,8 @@ static int _get_mirror_event(char *params)
        if (!dm_split_words(params, 1, 0, &p))
                goto out_parse;
 
-       if (!(num_devs = atoi(p)))
+       if (!(num_devs = atoi(p)) ||
+           (num_devs > DEFAULT_MIRROR_MAX_IMAGES) || (num_devs < 0))
                goto out_parse;
        p += strlen(p) + 1;
 
@@ -90,6 +92,7 @@ static int _get_mirror_event(char *params)
        if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5)
                goto out_parse;
 
+       /* FIXME: Code differs from lib/mirror/mirrored.c */
        dev_status_str = args[2 + num_devs];
        log_argc = atoi(args[3 + num_devs]);
        log_status_str = args[3 + num_devs + log_argc];
@@ -121,7 +124,7 @@ static int _get_mirror_event(char *params)
 out:
        dm_free(args);
        return r;
-       
+
 out_parse:
        dm_free(args);
        syslog(LOG_ERR, "Unable to parse mirror status string.");
@@ -133,32 +136,15 @@ static int _remove_failed_devices(const char *device)
        int r;
 #define CMD_SIZE 256   /* FIXME Use system restriction */
        char cmd_str[CMD_SIZE];
-       char *vg = NULL, *lv = NULL, *layer = NULL;
-
-       if (strlen(device) > 200)  /* FIXME Use real restriction */
-               return -ENAMETOOLONG;   /* FIXME These return code distinctions are not used so remove them! */
-
-       if (!dm_split_lvm_name(dmeventd_lvm2_pool(), device, &vg, &lv, &layer)) {
-               syslog(LOG_ERR, "Unable to determine VG name from %s.",
-                      device);
-               return -ENOMEM; /* FIXME Replace with generic error return - reason for failure has already got logged */
-       }
-
-       /* strip off the mirror component designations */
-       layer = strstr(lv, "_mlog");
-       if (layer)
-               *layer = '\0';
 
-       /* FIXME Is any sanity-checking required on %s? */
-       if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "lvconvert --config devices{ignore_suspended_devices=1} --repair --use-policies %s/%s", vg, lv)) {
-               /* this error should be caught above, but doesn't hurt to check again */
-               syslog(LOG_ERR, "Unable to form LVM command: Device name too long.");
+       if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
+                                 "lvconvert --config devices{ignore_suspended_devices=1} "
+                                 "--repair --use-policies", device))
                return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */
-       }
 
        r = dmeventd_lvm2_run(cmd_str);
 
-       syslog(LOG_INFO, "Repair of mirrored LV %s/%s %s.", vg, lv,
+       syslog(LOG_INFO, "Repair of mirrored device %s %s.", device,
               (r == ECMD_PROCESSED) ? "finished successfully" : "failed");
 
        return (r == ECMD_PROCESSED) ? 0 : -1;
@@ -227,9 +213,12 @@ int register_device(const char *device,
                    int minor __attribute__((unused)),
                    void **unused __attribute__((unused)))
 {
-       int r = dmeventd_lvm2_init();
+       if (!dmeventd_lvm2_init())
+               return 0;
+
        syslog(LOG_INFO, "Monitoring mirror device %s for events.", device);
-       return r;
+
+       return 1;
 }
 
 int unregister_device(const char *device,
@@ -241,5 +230,6 @@ int unregister_device(const char *device,
        syslog(LOG_INFO, "No longer monitoring mirror device %s for events.",
               device);
        dmeventd_lvm2_exit();
+
        return 1;
 }
diff --git a/daemons/dmeventd/plugins/raid/.exported_symbols b/daemons/dmeventd/plugins/raid/.exported_symbols
new file mode 100644 (file)
index 0000000..b88c705
--- /dev/null
@@ -0,0 +1,3 @@
+process_event
+register_device
+unregister_device
diff --git a/daemons/dmeventd/plugins/raid/Makefile.in b/daemons/dmeventd/plugins/raid/Makefile.in
new file mode 100644 (file)
index 0000000..a6b7788
--- /dev/null
@@ -0,0 +1,36 @@
+#
+# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = @top_builddir@
+
+INCLUDES += -I$(top_srcdir)/tools -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
+CLDFLAGS += -L$(top_builddir)/tools -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
+
+SOURCES = dmeventd_raid.c
+
+LIB_NAME = libdevmapper-event-lvm2raid
+LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
+LIB_VERSION = $(LIB_VERSION_LVM)
+
+CFLOW_LIST = $(SOURCES)
+CFLOW_LIST_TARGET = $(LIB_NAME).cflow
+
+include $(top_builddir)/make.tmpl
+
+LIBS += -ldevmapper-event-lvm2 -ldevmapper
+
+install_lvm2: install_dm_plugin
+
+install: install_lvm2
diff --git a/daemons/dmeventd/plugins/raid/dmeventd_raid.c b/daemons/dmeventd/plugins/raid/dmeventd_raid.c
new file mode 100644 (file)
index 0000000..a3ecdc1
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2005-2011 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "lib.h"
+
+#include "lvm2cmd.h"
+#include "errors.h"
+#include "libdevmapper-event.h"
+#include "dmeventd_lvm.h"
+
+#include <syslog.h> /* FIXME Replace syslog with multilog */
+/* FIXME Missing openlog? */
+/* FIXME Replace most syslogs with log_error() style messages and add complete context. */
+/* FIXME Reformat to 80 char lines. */
+
+/*
+ * run_repair is a close copy to
+ * plugins/mirror/dmeventd_mirror.c:_remove_failed_devices()
+ */
+static int run_repair(const char *device)
+{
+       int r;
+#define CMD_SIZE 256   /* FIXME Use system restriction */
+       char cmd_str[CMD_SIZE];
+
+       if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
+                                 "lvconvert --config devices{ignore_suspended_devices=1} "
+                                 "--repair --use-policies", device))
+               return -1;
+
+       r = dmeventd_lvm2_run(cmd_str);
+
+       if (r != ECMD_PROCESSED)
+               syslog(LOG_INFO, "Repair of RAID device %s failed.", device);
+
+       return (r == ECMD_PROCESSED) ? 0 : -1;
+}
+
+static int _process_raid_event(char *params, const char *device)
+{
+       int i, n, failure = 0;
+       char *p, *a[4];
+       char *raid_type;
+       char *num_devices;
+       char *health_chars;
+       char *resync_ratio;
+
+       /*
+        * RAID parms:     <raid_type> <#raid_disks> \
+        *                 <health chars> <resync ratio>
+        */
+       if (!dm_split_words(params, 4, 0, a)) {
+               syslog(LOG_ERR, "Failed to process status line for %s\n",
+                      device);
+               return -EINVAL;
+       }
+       raid_type = a[0];
+       num_devices = a[1];
+       health_chars = a[2];
+       resync_ratio = a[3];
+
+       if (!(n = atoi(num_devices))) {
+               syslog(LOG_ERR, "Failed to parse number of devices for %s: %s",
+                      device, num_devices);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < n; i++) {
+               switch (health_chars[i]) {
+               case 'A':
+                       /* Device is 'A'live and well */
+               case 'a':
+                       /* Device is 'a'live, but not yet in-sync */
+                       break;
+               case 'D':
+                       syslog(LOG_ERR,
+                              "Device #%d of %s array, %s, has failed.",
+                              i, raid_type, device);
+                       failure++;
+                       break;
+               default:
+                       /* Unhandled character returned from kernel */
+                       break;
+               }
+               if (failure)
+                       return run_repair(device);
+       }
+
+       p = strstr(resync_ratio, "/");
+       if (!p) {
+               syslog(LOG_ERR, "Failed to parse resync_ratio for %s: %s",
+                      device, resync_ratio);
+               return -EINVAL;
+       }
+       p[0] = '\0';
+       syslog(LOG_INFO, "%s array, %s, is %s in-sync.",
+              raid_type, device, strcmp(resync_ratio, p+1) ? "not" : "now");
+
+       return 0;
+}
+
+void process_event(struct dm_task *dmt,
+                  enum dm_event_mask event __attribute__((unused)),
+                  void **unused __attribute__((unused)))
+{
+       void *next = NULL;
+       uint64_t start, length;
+       char *target_type = NULL;
+       char *params;
+       const char *device = dm_task_get_name(dmt);
+
+       dmeventd_lvm2_lock();
+
+       do {
+               next = dm_get_next_target(dmt, next, &start, &length,
+                                         &target_type, &params);
+
+               if (!target_type) {
+                       syslog(LOG_INFO, "%s mapping lost.", device);
+                       continue;
+               }
+
+               if (strcmp(target_type, "raid")) {
+                       syslog(LOG_INFO, "%s has non-raid portion.", device);
+                       continue;
+               }
+
+               if (_process_raid_event(params, device))
+                       syslog(LOG_ERR, "Failed to process event for %s",
+                              device);
+       } while (next);
+
+       dmeventd_lvm2_unlock();
+}
+
+int register_device(const char *device,
+                   const char *uuid __attribute__((unused)),
+                   int major __attribute__((unused)),
+                   int minor __attribute__((unused)),
+                   void **unused __attribute__((unused)))
+{
+       if (!dmeventd_lvm2_init())
+               return 0;
+
+       syslog(LOG_INFO, "Monitoring RAID device %s for events.", device);
+
+       return 1;
+}
+
+int unregister_device(const char *device,
+                     const char *uuid __attribute__((unused)),
+                     int major __attribute__((unused)),
+                     int minor __attribute__((unused)),
+                     void **unused __attribute__((unused)))
+{
+       syslog(LOG_INFO, "No longer monitoring RAID device %s for events.",
+              device);
+       dmeventd_lvm2_exit();
+
+       return 1;
+}
index b8414b225d2f75774ac992d23746b71085f511db..a4cff15f983d865757c9170c23ea50fe79d95401 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
-# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
 #
 # This file is part of the LVM2.
 #
@@ -26,10 +26,8 @@ LIB_VERSION = $(LIB_VERSION_LVM)
 
 include $(top_builddir)/make.tmpl
 
-LIBS += -ldevmapper-event-lvm2 -ldevmapper
+LIBS += -ldevmapper-event-lvm2 -ldevmapper $(DAEMON_LIBS)
 
 install_lvm2: install_dm_plugin
 
 install: install_lvm2
-
-DISTCLEAN_TARGETS += .exported_symbols_generated
index 6fc9f562a2ae8c87ad7703d2bed4f823e8eae76f..205218abb7ae089c4c3a8e62f487be5ac51198f1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2007-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -19,8 +19,6 @@
 #include "libdevmapper-event.h"
 #include "dmeventd_lvm.h"
 
-#include "lvm-string.h"
-
 #include <sys/wait.h>
 #include <syslog.h> /* FIXME Replace syslog with multilog */
 /* FIXME Missing openlog? */
@@ -40,6 +38,12 @@ struct snap_status {
        int max;
 };
 
+struct dso_state {
+       int percent_check;
+       int known_size;
+       char cmd_str[1024];
+};
+
 /* FIXME possibly reconcile this with target_percent when we gain
    access to regular LVM library here. */
 static void _parse_snapshot_params(char *params, struct snap_status *status)
@@ -115,26 +119,9 @@ static int _run(const char *cmd, ...)
         return 1; /* all good */
 }
 
-static int _extend(const char *device)
+static int _extend(const char *cmd)
 {
-       char *vg = NULL, *lv = NULL, *layer = NULL;
-       char cmd_str[1024];
-       int r = 0;
-
-       if (!dm_split_lvm_name(dmeventd_lvm2_pool(), device, &vg, &lv, &layer)) {
-               syslog(LOG_ERR, "Unable to determine VG name from %s.", device);
-               return 0;
-       }
-       if (sizeof(cmd_str) <= snprintf(cmd_str, sizeof(cmd_str),
-                                       "lvextend --use-policies %s/%s", vg, lv)) {
-               syslog(LOG_ERR, "Unable to form LVM command: Device name too long.");
-               return 0;
-       }
-
-       r = dmeventd_lvm2_run(cmd_str);
-       syslog(LOG_INFO, "Extension of snapshot %s/%s %s.", vg, lv,
-              (r == ECMD_PROCESSED) ? "finished successfully" : "failed");
-       return r == ECMD_PROCESSED;
+       return dmeventd_lvm2_run(cmd) == ECMD_PROCESSED;
 }
 
 static void _umount(const char *device, int major, int minor)
@@ -155,7 +142,8 @@ static void _umount(const char *device, int major, int minor)
                        break; /* eof, likely */
 
                /* words[0] is the mount point and words[1] is the device path */
-               dm_split_words(buffer, 3, 0, words);
+               if (dm_split_words(buffer, 3, 0, words) < 2)
+                       continue;
 
                /* find the major/minor of the device */
                if (stat(words[0], &st))
@@ -164,9 +152,9 @@ static void _umount(const char *device, int major, int minor)
                if (S_ISBLK(st.st_mode) &&
                    major(st.st_rdev) == major &&
                    minor(st.st_rdev) == minor) {
-                       syslog(LOG_ERR, "Unmounting invalid snapshot %s from %s.", device, words[1]);
+                       syslog(LOG_ERR, "Unmounting invalid snapshot %s from %s.\n", device, words[1]);
                         if (!_run(UMOUNT_COMMAND, "-fl", words[1], NULL))
-                                syslog(LOG_ERR, "Failed to umount snapshot %s from %s: %s.",
+                                syslog(LOG_ERR, "Failed to umount snapshot %s from %s: %s.\n",
                                        device, words[1], strerror(errno));
                }
        }
@@ -185,10 +173,11 @@ void process_event(struct dm_task *dmt,
        char *params;
        struct snap_status status = { 0 };
        const char *device = dm_task_get_name(dmt);
-       int percent, *percent_check = (int*)private;
+       int percent;
+       struct dso_state *state = *private;
 
        /* No longer monitoring, waiting for remove */
-       if (!*percent_check)
+       if (!state->percent_check)
                return;
 
        dmeventd_lvm2_lock();
@@ -200,7 +189,6 @@ void process_event(struct dm_task *dmt,
        _parse_snapshot_params(params, &status);
 
        if (status.invalid) {
-               syslog(LOG_ERR, "Trying to umount invalid snapshot %s...\n", device);
                struct dm_info info;
                if (dm_task_get_info(dmt, &info)) {
                        dmeventd_lvm2_unlock();
@@ -209,27 +197,35 @@ void process_event(struct dm_task *dmt,
                } /* else; too bad, but this is best-effort thing... */
        }
 
+       /* Snapshot size had changed. Clear the threshold. */
+       if (state->known_size != status.max) {
+               state->percent_check = CHECK_MINIMUM;
+               state->known_size = status.max;
+       }
+
        /*
         * If the snapshot has been invalidated or we failed to parse
         * the status string. Report the full status string to syslog.
         */
        if (status.invalid || !status.max) {
                syslog(LOG_ERR, "Snapshot %s changed state to: %s\n", device, params);
-               *percent_check = 0;
+               state->percent_check = 0;
                goto out;
        }
 
        percent = 100 * status.used / status.max;
-       if (percent >= *percent_check) {
+       if (percent >= state->percent_check) {
                /* Usage has raised more than CHECK_STEP since the last
                   time. Run actions. */
-               *percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
+               state->percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
+
                if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
                        syslog(LOG_WARNING, "Snapshot %s is now %i%% full.\n", device, percent);
                /* Try to extend the snapshot, in accord with user-set policies */
-               if (!_extend(device))
-                       syslog(LOG_ERR, "Failed to extend snapshot %s.", device);
+               if (!_extend(state->cmd_str))
+                       syslog(LOG_ERR, "Failed to extend snapshot %s.\n", device);
        }
+
 out:
        dmeventd_lvm2_unlock();
 }
@@ -240,23 +236,46 @@ int register_device(const char *device,
                    int minor __attribute__((unused)),
                    void **private)
 {
-       int *percent_check = (int*)private;
-       int r = dmeventd_lvm2_init();
+       struct dso_state *state;
+
+       if (!dmeventd_lvm2_init())
+               goto out;
 
-       *percent_check = CHECK_MINIMUM;
+       if (!(state = dm_zalloc(sizeof(*state))))
+               goto bad;
+
+       if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(),
+                                   state->cmd_str, sizeof(state->cmd_str),
+                                  "lvextend --use-policies", device))
+               goto bad;
+
+       state->percent_check = CHECK_MINIMUM;
+       state->known_size = 0;
+       *private = state;
 
        syslog(LOG_INFO, "Monitoring snapshot %s\n", device);
-       return r;
+
+       return 1;
+bad:
+       dm_free(state);
+       dmeventd_lvm2_exit();
+out:
+       syslog(LOG_ERR, "Failed to monitor snapshot %s.\n", device);
+
+       return 0;
 }
 
 int unregister_device(const char *device,
                      const char *uuid __attribute__((unused)),
                      int major __attribute__((unused)),
                      int minor __attribute__((unused)),
-                     void **unused __attribute__((unused)))
+                     void **private)
 {
-       syslog(LOG_INFO, "No longer monitoring snapshot %s\n",
-              device);
+       struct dso_state *state = *private;
+
+       syslog(LOG_INFO, "No longer monitoring snapshot %s\n", device);
+       dm_free(state);
        dmeventd_lvm2_exit();
+
        return 1;
 }
diff --git a/daemons/dmeventd/plugins/thin/.exported_symbols b/daemons/dmeventd/plugins/thin/.exported_symbols
new file mode 100644 (file)
index 0000000..b88c705
--- /dev/null
@@ -0,0 +1,3 @@
+process_event
+register_device
+unregister_device
diff --git a/daemons/dmeventd/plugins/thin/Makefile.in b/daemons/dmeventd/plugins/thin/Makefile.in
new file mode 100644 (file)
index 0000000..e964ab5
--- /dev/null
@@ -0,0 +1,36 @@
+#
+# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = @top_builddir@
+
+INCLUDES += -I$(top_srcdir)/tools -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
+CLDFLAGS += -L$(top_builddir)/tools -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
+
+SOURCES = dmeventd_thin.c
+
+LIB_NAME = libdevmapper-event-lvm2thin
+LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
+LIB_VERSION = $(LIB_VERSION_LVM)
+
+CFLOW_LIST = $(SOURCES)
+CFLOW_LIST_TARGET = $(LIB_NAME).cflow
+
+include $(top_builddir)/make.tmpl
+
+LIBS += -ldevmapper-event-lvm2 -ldevmapper
+
+install_lvm2: install_dm_plugin
+
+install: install_lvm2
diff --git a/daemons/dmeventd/plugins/thin/dmeventd_thin.c b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
new file mode 100644 (file)
index 0000000..a1af4c0
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "lib.h"
+
+#include "lvm2cmd.h"
+#include "errors.h"
+#include "libdevmapper-event.h"
+#include "dmeventd_lvm.h"
+
+#include <sys/wait.h>
+#include <syslog.h> /* FIXME Replace syslog with multilog */
+/* FIXME Missing openlog? */
+
+/* First warning when thin is 80% full. */
+#define WARNING_THRESH 80
+/* Run a check every 5%. */
+#define CHECK_STEP 5
+/* Do not bother checking thins less than 50% full. */
+#define CHECK_MINIMUM 50
+
+#define UMOUNT_COMMAND "/bin/umount"
+
+#define THIN_DEBUG 0
+
+struct dso_state {
+       struct dm_pool *mem;
+       int metadata_percent_check;
+       int data_percent_check;
+       uint64_t known_metadata_size;
+       uint64_t known_data_size;
+       char cmd_str[1024];
+};
+
+
+/* TODO - move this mountinfo code into library to be reusable */
+#ifdef linux
+#  include "kdev_t.h"
+#else
+#  define MAJOR(x) major((x))
+#  define MINOR(x) minor((x))
+#  define MKDEV(x,y) makedev((x),(y))
+#endif
+
+/* Macros to make string defines */
+#define TO_STRING_EXP(A) #A
+#define TO_STRING(A) TO_STRING_EXP(A)
+
+static int _is_octal(int a)
+{
+       return (((a) & ~7) == '0');
+}
+
+/* Convert mangled mountinfo into normal ASCII string */
+static void _unmangle_mountinfo_string(const char *src, char *buf)
+{
+       if (!src)
+               return;
+
+       while (*src) {
+               if ((*src == '\\') &&
+                   _is_octal(src[1]) && _is_octal(src[2]) && _is_octal(src[3])) {
+                       *buf++ = 64 * (src[1] & 7) + 8 * (src[2] & 7) + (src[3] & 7);
+                       src += 4;
+               } else
+                       *buf++ = *src++;
+       }
+       *buf = '\0';
+}
+
+/* Parse one line of mountinfo */
+static int _parse_mountinfo_line(const char *line, unsigned *maj, unsigned *min, char *buf)
+{
+       char root[PATH_MAX + 1];
+       char target[PATH_MAX + 1];
+
+       /* TODO: maybe detect availability of  %ms  glib support ? */
+       if (sscanf(line, "%*u %*u %u:%u %" TO_STRING(PATH_MAX)
+                  "s %" TO_STRING(PATH_MAX) "s",
+                  maj, min, root, target) < 4)
+               return 0;
+
+       _unmangle_mountinfo_string(target, buf);
+
+#if THIN_DEBUG
+       syslog(LOG_DEBUG, "Mounted  %u:%u  %s", *maj, *min, buf);
+#endif
+
+       return 1;
+}
+
+/* Get dependencies for device, and try to find matching device */
+static int _has_deps(const char *name, int tp_major, int tp_minor, int *dev_minor)
+{
+       struct dm_task *dmt;
+       const struct dm_deps *deps;
+       struct dm_info info;
+       int major, minor;
+       int r = 0;
+
+       if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
+               return 0;
+
+       if (!dm_task_set_name(dmt, name))
+               goto out;
+
+       if (!dm_task_no_open_count(dmt))
+               goto out;
+
+       if (!dm_task_run(dmt))
+               goto out;
+
+       if (!dm_task_get_info(dmt, &info))
+               goto out;
+
+       if (!(deps = dm_task_get_deps(dmt)))
+               goto out;
+
+       if (!info.exists || deps->count != 1)
+               goto out;
+
+       major = (int) MAJOR(deps->device[0]);
+       minor = (int) MINOR(deps->device[0]);
+       if ((major != tp_major) || (minor != tp_minor))
+               goto out;
+
+       *dev_minor = info.minor;
+
+#if THIN_DEBUG
+       {
+               char dev_name[PATH_MAX];
+               if (dm_device_get_name(major, minor, 0, dev_name, sizeof(dev_name)))
+                       syslog(LOG_DEBUG, "Found %s (%u:%u) depends on %s",
+                              name, major, *dev_minor, dev_name);
+       }
+#endif
+       r = 1;
+out:
+       dm_task_destroy(dmt);
+
+       return r;
+}
+
+/* Get all active devices */
+static int _find_all_devs(dm_bitset_t bs, int tp_major, int tp_minor)
+{
+       struct dm_task *dmt;
+       struct dm_names *names;
+       unsigned next = 0;
+       int minor, r = 1;
+
+       if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
+               return 0;
+
+       if (!dm_task_run(dmt)) {
+               r = 0;
+               goto out;
+       }
+
+       if (!(names = dm_task_get_names(dmt))) {
+               r = 0;
+               goto out;
+       }
+
+       if (!names->dev)
+               goto out;
+
+       do {
+               names = (struct dm_names *)((char *) names + next);
+               if (_has_deps(names->name, tp_major, tp_minor, &minor))
+                       dm_bit_set(bs, minor);
+               next = names->next;
+       } while (next);
+
+out:
+       dm_task_destroy(dmt);
+
+       return r;
+}
+
+static int _extend(struct dso_state *state)
+{
+#if THIN_DEBUG
+       syslog(LOG_INFO, "dmeventd executes: %s.\n", state->cmd_str);
+#endif
+       return (dmeventd_lvm2_run(state->cmd_str) == ECMD_PROCESSED);
+}
+
+static int _run(const char *cmd, ...)
+{
+       va_list ap;
+       int argc = 1; /* for argv[0], i.e. cmd */
+       int i = 0;
+       const char **argv;
+       pid_t pid = fork();
+       int status;
+
+       if (pid == 0) { /* child */
+               va_start(ap, cmd);
+               while (va_arg(ap, const char *))
+                       ++argc;
+               va_end(ap);
+
+               /* + 1 for the terminating NULL */
+               argv = alloca(sizeof(const char *) * (argc + 1));
+
+               argv[0] = cmd;
+                va_start(ap, cmd);
+               while ((argv[++i] = va_arg(ap, const char *)));
+               va_end(ap);
+
+               execvp(cmd, (char **)argv);
+               syslog(LOG_ERR, "Failed to execute %s: %s.\n", cmd, strerror(errno));
+               exit(127);
+       }
+
+       if (pid > 0) { /* parent */
+               if (waitpid(pid, &status, 0) != pid)
+                       return 0; /* waitpid failed */
+               if (!WIFEXITED(status) || WEXITSTATUS(status))
+                       return 0; /* the child failed */
+       }
+
+       if (pid < 0)
+               return 0; /* fork failed */
+
+       return 1; /* all good */
+}
+
+/*
+ * Find all thin pool users and try to umount them.
+ * TODO: work with read-only thin pool support
+ */
+static void _umount(struct dm_task *dmt, const char *device)
+{
+       static const char mountinfo[] = "/proc/self/mountinfo";
+       static const size_t MINORS = 4096;
+       FILE *minfo;
+       char buffer[4096];
+       char target[PATH_MAX];
+       struct dm_info info;
+       unsigned maj, min;
+       dm_bitset_t minors; /* Bitset for active thin pool minors */
+
+       if (!dm_task_get_info(dmt, &info))
+               return;
+
+       dmeventd_lvm2_unlock();
+
+       if (!(minors = dm_bitset_create(NULL, MINORS))) {
+               syslog(LOG_ERR, "Failed to allocate bitset. Not unmounting %s.\n", device);
+               goto out;
+       }
+
+       if (!(minfo = fopen(mountinfo, "r"))) {
+               syslog(LOG_ERR, "Could not read %s. Not umounting %s.\n", mountinfo, device);
+               goto out;
+       }
+
+       if (!_find_all_devs(minors, info.major, info.minor)) {
+               syslog(LOG_ERR, "Failed to detect mounted volumes for %s.\n", device);
+               goto out;
+       }
+
+       while (!feof(minfo)) {
+               /* read mountinfo line */
+               if (!fgets(buffer, sizeof(buffer), minfo))
+                       break; /* eof, likely */
+
+               if (_parse_mountinfo_line(buffer, &maj, &min, target) &&
+                   (maj == info.major) && dm_bit(minors, min)) {
+                       syslog(LOG_INFO, "Unmounting thin volume %s from %s.\n",
+                              device, target);
+                       if (!_run(UMOUNT_COMMAND, "-fl", target, NULL))
+                               syslog(LOG_ERR, "Failed to umount thin %s from %s: %s.\n",
+                                      device, target, strerror(errno));
+               }
+       }
+
+       if (fclose(minfo))
+               syslog(LOG_ERR, "Failed to close %s\n", mountinfo);
+
+       dm_bitset_destroy(minors);
+out:
+       dmeventd_lvm2_lock();
+}
+
+void process_event(struct dm_task *dmt,
+                  enum dm_event_mask event __attribute__((unused)),
+                  void **private)
+{
+       const char *device = dm_task_get_name(dmt);
+       int percent;
+       struct dso_state *state = *private;
+       struct dm_status_thin_pool *tps = NULL;
+       void *next = NULL;
+       uint64_t start, length;
+       char *target_type = NULL;
+       char *params;
+
+#if 0
+       /* No longer monitoring, waiting for remove */
+       if (!state->meta_percent_check && !state->data_percent_check)
+               return;
+#endif
+       dmeventd_lvm2_lock();
+
+       dm_get_next_target(dmt, next, &start, &length, &target_type, &params);
+
+       if (!target_type || (strcmp(target_type, "thin-pool") != 0)) {
+               syslog(LOG_ERR, "Invalid target type.\n");
+               goto out;
+       }
+
+       if (!dm_get_status_thin_pool(state->mem, params, &tps)) {
+               syslog(LOG_ERR, "Failed to parse status.\n");
+               _umount(dmt, device);
+               goto out;
+       }
+
+#if THIN_DEBUG
+       syslog(LOG_INFO, "%p: Got status %" PRIu64 " / %" PRIu64
+              " %" PRIu64  " / %" PRIu64 ".\n", state,
+              tps->used_metadata_blocks, tps->total_metadata_blocks,
+              tps->used_data_blocks, tps->total_data_blocks);
+#endif
+
+       /* Thin pool size had changed. Clear the threshold. */
+       if (state->known_metadata_size != tps->total_metadata_blocks) {
+               state->metadata_percent_check = CHECK_MINIMUM;
+               state->known_metadata_size = tps->total_metadata_blocks;
+       }
+
+       if (state->known_data_size != tps->total_data_blocks) {
+               state->data_percent_check = CHECK_MINIMUM;
+               state->known_data_size = tps->total_data_blocks;
+       }
+
+       percent = 100 * tps->used_metadata_blocks / tps->total_metadata_blocks;
+       if (percent >= state->metadata_percent_check) {
+               /*
+                * Usage has raised more than CHECK_STEP since the last
+                * time. Run actions.
+                */
+               state->metadata_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
+
+               /* FIXME: extension of metadata needs to be written! */
+               if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
+                       syslog(LOG_WARNING, "Thin metadata %s is now %i%% full.\n",
+                              device, percent);
+                /* Try to extend the metadata, in accord with user-set policies */
+               if (!_extend(state)) {
+                       syslog(LOG_ERR, "Failed to extend thin metadata %s.\n",
+                              device);
+                       _umount(dmt, device);
+               }
+               /* FIXME: hmm READ-ONLY switch should happen in error path */
+       }
+
+       percent = 100 * tps->used_data_blocks / tps->total_data_blocks;
+       if (percent >= state->data_percent_check) {
+               /*
+                * Usage has raised more than CHECK_STEP since
+                * the last time. Run actions.
+                */
+               state->data_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
+
+               if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
+                       syslog(LOG_WARNING, "Thin %s is now %i%% full.\n", device, percent);
+               /* Try to extend the thin data, in accord with user-set policies */
+               if (!_extend(state)) {
+                       syslog(LOG_ERR, "Failed to extend thin %s.\n", device);
+                       state->data_percent_check = 0;
+                       _umount(dmt, device);
+               }
+               /* FIXME: hmm READ-ONLY switch should happen in error path */
+       }
+out:
+       if (tps)
+               dm_pool_free(state->mem, tps);
+
+       dmeventd_lvm2_unlock();
+}
+
+int register_device(const char *device,
+                   const char *uuid __attribute__((unused)),
+                   int major __attribute__((unused)),
+                   int minor __attribute__((unused)),
+                   void **private)
+{
+       struct dm_pool *statemem = NULL;
+       struct dso_state *state;
+
+       if (!dmeventd_lvm2_init())
+               goto bad;
+
+       if (!(statemem = dm_pool_create("thin_pool_state", 2048)) ||
+           !(state = dm_pool_zalloc(statemem, sizeof(*state))) ||
+           !dmeventd_lvm2_command(statemem, state->cmd_str,
+                                  sizeof(state->cmd_str),
+                                  "lvextend --use-policies",
+                                  device)) {
+               if (statemem)
+                       dm_pool_destroy(statemem);
+               dmeventd_lvm2_exit();
+               goto bad;
+       }
+
+       state->mem = statemem;
+       state->metadata_percent_check = CHECK_MINIMUM;
+       state->data_percent_check = CHECK_MINIMUM;
+       *private = state;
+
+       syslog(LOG_INFO, "Monitoring thin %s.\n", device);
+
+       return 1;
+bad:
+       syslog(LOG_ERR, "Failed to monitor thin %s.\n", device);
+
+       return 0;
+}
+
+int unregister_device(const char *device,
+                     const char *uuid __attribute__((unused)),
+                     int major __attribute__((unused)),
+                     int minor __attribute__((unused)),
+                     void **private)
+{
+       struct dso_state *state = *private;
+
+       syslog(LOG_INFO, "No longer monitoring thin %s.\n", device);
+       dm_pool_destroy(state->mem);
+       dmeventd_lvm2_exit();
+
+       return 1;
+}
diff --git a/daemons/lvmetad/Makefile.in b/daemons/lvmetad/Makefile.in
new file mode 100644 (file)
index 0000000..35aa4ab
--- /dev/null
@@ -0,0 +1,59 @@
+#
+# Copyright (C) 2011-2012 Red Hat, Inc.
+#
+# This file is part of LVM2.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU Lesser General Public License v.2.1.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = @top_builddir@
+
+SOURCES = lvmetad-core.c
+SOURCES2 = testclient.c
+
+TARGETS = lvmetad lvmetad-testclient
+
+.PHONY: install_lvmetad
+
+CFLOW_LIST = $(SOURCES)
+CFLOW_LIST_TARGET = $(LIB_NAME).cflow
+CFLOW_TARGET = lvmetad
+
+include $(top_builddir)/make.tmpl
+
+INCLUDES += -I$(top_srcdir)/libdaemon/server
+LVMLIBS = -ldaemonserver $(LVMINTERNAL_LIBS) -ldevmapper
+
+LIBS += $(PTHREAD_LIBS)
+
+LDFLAGS += -L$(top_builddir)/libdaemon/server
+CLDFLAGS += -L$(top_builddir)/libdaemon/server
+
+lvmetad: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
+                   $(top_builddir)/libdaemon/server/libdaemonserver.a
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
+       $(DL_LIBS) $(LVMLIBS) $(LIBS) -rdynamic
+
+# TODO: No idea. No idea how to test either.
+#ifneq ("$(CFLOW_CMD)", "")
+#CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
+#-include $(top_builddir)/libdm/libdevmapper.cflow
+#-include $(top_builddir)/lib/liblvm-internal.cflow
+#-include $(top_builddir)/lib/liblvm2cmd.cflow
+#-include $(top_builddir)/daemons/dmeventd/$(LIB_NAME).cflow
+#-include $(top_builddir)/daemons/dmeventd/plugins/mirror/$(LIB_NAME)-lvm2mirror.cflow
+#endif
+
+install_lvmetad: lvmetad
+       $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
+
+install_lvm2: install_lvmetad
+
+install: install_lvm2
diff --git a/daemons/lvmetad/lvmetad-client.h b/daemons/lvmetad/lvmetad-client.h
new file mode 100644 (file)
index 0000000..fe8eedc
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2011-2012 Red Hat, Inc.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LVM_LVMETAD_CLIENT_H
+#define _LVM_LVMETAD_CLIENT_H
+
+#include "daemon-client.h"
+
+struct volume_group;
+
+/* Different types of replies we may get from lvmetad. */
+
+typedef struct {
+       daemon_reply r;
+       const char **uuids; /* NULL terminated array */
+} lvmetad_uuidlist;
+
+typedef struct {
+       daemon_reply r;
+       struct dm_config_tree *cft;
+} lvmetad_vg;
+
+/* Get a list of VG UUIDs that match a given VG name. */
+lvmetad_uuidlist lvmetad_lookup_vgname(daemon_handle h, const char *name);
+
+/* Get the metadata of a single VG, identified by UUID. */
+lvmetad_vg lvmetad_get_vg(daemon_handle h, const char *uuid);
+
+/*
+ * Add and remove PVs on demand. Udev-driven systems will use this interface
+ * instead of scanning.
+ */
+daemon_reply lvmetad_add_pv(daemon_handle h, const char *pv_uuid, const char *mda_content);
+daemon_reply lvmetad_remove_pv(daemon_handle h, const char *pv_uuid);
+
+/* Trigger a full disk scan, throwing away all caches. XXX do we eventually want
+ * this? Probably not yet, anyway.
+ *     daemon_reply lvmetad_rescan(daemon_handle h);
+ */
+
+/*
+ * Update the version of metadata of a volume group. The VG has to be locked for
+ * writing for this, and the VG metadata here has to match whatever has been
+ * written to the disk (under this lock). This initially avoids the requirement
+ * for lvmetad to write to disk (in later revisions, lvmetad_supersede_vg may
+ * also do the writing, or we probably add another function to do that).
+ */
+daemon_reply lvmetad_supersede_vg(daemon_handle h, struct volume_group *vg);
+
+/* Wrappers to open/close connection */
+
+static inline daemon_handle lvmetad_open(const char *socket)
+{
+       daemon_info lvmetad_info = {
+               .path = "lvmetad",
+               .socket = socket ?: DEFAULT_RUN_DIR "/lvmetad.socket",
+               .protocol = "lvmetad",
+               .protocol_version = 1,
+               .autostart = 0
+       };
+
+       return daemon_open(lvmetad_info);
+}
+
+static inline void lvmetad_close(daemon_handle h)
+{
+       return daemon_close(h);
+}
+
+#endif
diff --git a/daemons/lvmetad/lvmetad-core.c b/daemons/lvmetad/lvmetad-core.c
new file mode 100644 (file)
index 0000000..0a1c884
--- /dev/null
@@ -0,0 +1,1204 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define _XOPEN_SOURCE 500  /* pthread */
+
+#include "configure.h"
+#include "daemon-io.h"
+#include "config-util.h"
+#include "daemon-server.h"
+#include "daemon-log.h"
+#include "lvm-version.h"
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <unistd.h>
+
+typedef struct {
+       log_state *log; /* convenience */
+       const char *log_config;
+
+       struct dm_hash_table *pvid_to_pvmeta;
+       struct dm_hash_table *device_to_pvid; /* shares locks with above */
+
+       struct dm_hash_table *vgid_to_metadata;
+       struct dm_hash_table *vgid_to_vgname;
+       struct dm_hash_table *vgname_to_vgid;
+       struct dm_hash_table *pvid_to_vgid;
+       struct {
+               struct dm_hash_table *vg;
+               pthread_mutex_t vg_lock_map;
+               pthread_mutex_t pvid_to_pvmeta;
+               pthread_mutex_t vgid_to_metadata;
+               pthread_mutex_t pvid_to_vgid;
+       } lock;
+       char token[128];
+       pthread_mutex_t token_lock;
+} lvmetad_state;
+
+static void destroy_metadata_hashes(lvmetad_state *s)
+{
+       struct dm_hash_node *n = NULL;
+
+       n = dm_hash_get_first(s->vgid_to_metadata);
+       while (n) {
+               dm_config_destroy(dm_hash_get_data(s->vgid_to_metadata, n));
+               n = dm_hash_get_next(s->vgid_to_metadata, n);
+       }
+
+       n = dm_hash_get_first(s->pvid_to_pvmeta);
+       while (n) {
+               dm_config_destroy(dm_hash_get_data(s->pvid_to_pvmeta, n));
+               n = dm_hash_get_next(s->pvid_to_pvmeta, n);
+       }
+       dm_hash_destroy(s->pvid_to_pvmeta);
+       dm_hash_destroy(s->vgid_to_metadata);
+       dm_hash_destroy(s->vgid_to_vgname);
+       dm_hash_destroy(s->vgname_to_vgid);
+
+       n = dm_hash_get_first(s->device_to_pvid);
+       while (n) {
+               dm_free(dm_hash_get_data(s->device_to_pvid, n));
+               n = dm_hash_get_next(s->device_to_pvid, n);
+       }
+
+       dm_hash_destroy(s->device_to_pvid);
+       dm_hash_destroy(s->pvid_to_vgid);
+}
+
+static void create_metadata_hashes(lvmetad_state *s)
+{
+       s->pvid_to_pvmeta = dm_hash_create(32);
+       s->device_to_pvid = dm_hash_create(32);
+       s->vgid_to_metadata = dm_hash_create(32);
+       s->vgid_to_vgname = dm_hash_create(32);
+       s->pvid_to_vgid = dm_hash_create(32);
+       s->vgname_to_vgid = dm_hash_create(32);
+}
+
+static void lock_pvid_to_pvmeta(lvmetad_state *s) {
+       pthread_mutex_lock(&s->lock.pvid_to_pvmeta); }
+static void unlock_pvid_to_pvmeta(lvmetad_state *s) {
+       pthread_mutex_unlock(&s->lock.pvid_to_pvmeta); }
+
+static void lock_vgid_to_metadata(lvmetad_state *s) {
+       pthread_mutex_lock(&s->lock.vgid_to_metadata); }
+static void unlock_vgid_to_metadata(lvmetad_state *s) {
+       pthread_mutex_unlock(&s->lock.vgid_to_metadata); }
+
+static void lock_pvid_to_vgid(lvmetad_state *s) {
+       pthread_mutex_lock(&s->lock.pvid_to_vgid); }
+static void unlock_pvid_to_vgid(lvmetad_state *s) {
+       pthread_mutex_unlock(&s->lock.pvid_to_vgid); }
+
+static response reply_fail(const char *reason)
+{
+       return daemon_reply_simple("failed", "reason = %s", reason, NULL);
+}
+
+static response reply_unknown(const char *reason)
+{
+       return daemon_reply_simple("unknown", "reason = %s", reason, NULL);
+}
+
+/*
+ * TODO: It may be beneficial to clean up the vg lock hash from time to time,
+ * since if we have many "rogue" requests for nonexistent things, we will keep
+ * allocating memory that we never release. Not good.
+ */
+static struct dm_config_tree *lock_vg(lvmetad_state *s, const char *id) {
+       pthread_mutex_t *vg;
+       struct dm_config_tree *cft;
+
+       pthread_mutex_lock(&s->lock.vg_lock_map);
+       vg = dm_hash_lookup(s->lock.vg, id);
+       if (!vg) {
+               pthread_mutexattr_t rec;
+               pthread_mutexattr_init(&rec);
+               pthread_mutexattr_settype(&rec, PTHREAD_MUTEX_RECURSIVE_NP);
+               if (!(vg = malloc(sizeof(pthread_mutex_t))))
+                        return NULL;
+               pthread_mutex_init(vg, &rec);
+               if (!dm_hash_insert(s->lock.vg, id, vg)) {
+                       free(vg);
+                       return NULL;
+               }
+       }
+       /* We never remove items from s->lock.vg => the pointer remains valid. */
+       pthread_mutex_unlock(&s->lock.vg_lock_map);
+
+       DEBUGLOG(s, "locking VG %s", id);
+       pthread_mutex_lock(vg);
+
+       /* Protect against structure changes of the vgid_to_metadata hash. */
+       lock_vgid_to_metadata(s);
+       cft = dm_hash_lookup(s->vgid_to_metadata, id);
+       unlock_vgid_to_metadata(s);
+       return cft;
+}
+
+static void unlock_vg(lvmetad_state *s, const char *id) {
+       pthread_mutex_t *vg;
+
+       DEBUGLOG(s, "unlocking VG %s", id);
+       /* Protect the s->lock.vg structure from concurrent access. */
+       pthread_mutex_lock(&s->lock.vg_lock_map);
+       if ((vg = dm_hash_lookup(s->lock.vg, id)))
+               pthread_mutex_unlock(vg);
+       pthread_mutex_unlock(&s->lock.vg_lock_map);
+}
+
+static struct dm_config_node *pvs(struct dm_config_node *vg)
+{
+       struct dm_config_node *pv = dm_config_find_node(vg, "metadata/physical_volumes");
+       if (pv)
+               pv = pv->child;
+       return pv;
+}
+
+static void filter_metadata(struct dm_config_node *vg) {
+       struct dm_config_node *pv = pvs(vg);
+       while (pv) {
+               struct dm_config_node *item = pv->child;
+               while (item) {
+                       /* Remove the advisory device nodes. */
+                       if (item->sib && !strcmp(item->sib->key, "device"))
+                               item->sib = item->sib->sib;
+                       item = item->sib;
+               }
+               pv = pv->sib;
+       }
+       vg->sib = NULL; /* Drop any trailing garbage. */
+}
+
+static void merge_pvmeta(struct dm_config_node *pv, struct dm_config_node *pvmeta)
+{
+       struct dm_config_node *tmp;
+
+       if (!pvmeta)
+               return;
+
+       tmp = pvmeta;
+       while (tmp->sib) {
+               /* drop the redundant ID and dev_size nodes */
+               if (!strcmp(tmp->sib->key, "id") || !strcmp(tmp->sib->key, "dev_size"))
+                       tmp->sib = tmp->sib->sib;
+               if (!tmp->sib) break;
+               tmp = tmp->sib;
+               tmp->parent = pv;
+       }
+       tmp->sib = pv->child;
+       pv->child = pvmeta;
+       pvmeta->parent = pv;
+}
+
+/* Either the "big" vgs lock, or a per-vg lock needs to be held before entering
+ * this function. */
+static int update_pv_status(lvmetad_state *s,
+                           struct dm_config_tree *cft,
+                           struct dm_config_node *vg, int act)
+{
+       struct dm_config_node *pv;
+       int complete = 1;
+       const char *uuid;
+       struct dm_config_tree *pvmeta;
+
+       lock_pvid_to_pvmeta(s);
+
+       for (pv = pvs(vg); pv; pv = pv->sib) {
+               if (!(uuid = dm_config_find_str(pv->child, "id", NULL)))
+                       continue;
+
+               pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, uuid);
+               if (act) {
+                       set_flag(cft, pv, "status", "MISSING", !pvmeta);
+                       if (pvmeta) {
+                               struct dm_config_node *pvmeta_cn =
+                                       dm_config_clone_node(cft, pvmeta->root->child, 1);
+                               merge_pvmeta(pv, pvmeta_cn);
+                       }
+               }
+               if (!pvmeta) {
+                       complete = 0;
+                       if (!act) { /* optimisation */
+                               unlock_pvid_to_pvmeta(s);
+                               return complete;
+                       }
+               }
+       }
+       unlock_pvid_to_pvmeta(s);
+
+       return complete;
+}
+
+static struct dm_config_node *make_pv_node(lvmetad_state *s, const char *pvid,
+                                          struct dm_config_tree *cft,
+                                          struct dm_config_node *parent,
+                                          struct dm_config_node *pre_sib)
+{
+       struct dm_config_tree *pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid);
+       const char *vgid = dm_hash_lookup(s->pvid_to_vgid, pvid), *vgname = NULL;
+       struct dm_config_node *pv;
+       struct dm_config_node *cn = NULL;
+
+       if (!pvmeta)
+               return NULL;
+
+       if (vgid) {
+               lock_vgid_to_metadata(s); // XXX
+               vgname = dm_hash_lookup(s->vgid_to_vgname, vgid);
+               unlock_vgid_to_metadata(s);
+       }
+
+       /* Nick the pvmeta config tree. */
+       if (!(pv = dm_config_clone_node(cft, pvmeta->root, 0)))
+               return 0;
+
+       if (pre_sib)
+               pre_sib->sib = pv;
+       if (parent && !parent->child)
+               parent->child = pv;
+       pv->parent = parent;
+       pv->key = pvid;
+
+       /* Add the "variable" bits to it. */
+
+       if (vgid && strcmp(vgid, "#orphan"))
+               cn = make_text_node(cft, "vgid", vgid, pv, cn);
+       if (vgname)
+               cn = make_text_node(cft, "vgname", vgname, pv, cn);
+
+       return pv;
+}
+
+static response pv_list(lvmetad_state *s, request r)
+{
+       struct dm_config_node *cn = NULL, *cn_pvs;
+       struct dm_hash_node *n;
+       const char *id;
+       response res;
+
+       buffer_init( &res.buffer );
+
+       if (!(res.cft = dm_config_create()))
+               return res; /* FIXME error reporting */
+
+       /* The response field */
+       res.cft->root = make_text_node(res.cft, "response", "OK", NULL, NULL);
+       cn_pvs = make_config_node(res.cft, "physical_volumes", NULL, res.cft->root);
+
+       lock_pvid_to_pvmeta(s);
+
+       for (n = dm_hash_get_first(s->pvid_to_pvmeta); n;
+            n = dm_hash_get_next(s->pvid_to_pvmeta, n)) {
+               id = dm_hash_get_key(s->pvid_to_pvmeta, n);
+               cn = make_pv_node(s, id, res.cft, cn_pvs, cn);
+       }
+
+       unlock_pvid_to_pvmeta(s);
+
+       return res;
+}
+
+static response pv_lookup(lvmetad_state *s, request r)
+{
+       const char *pvid = daemon_request_str(r, "uuid", NULL);
+       int64_t devt = daemon_request_int(r, "device", 0);
+       response res;
+       struct dm_config_node *pv;
+
+       buffer_init( &res.buffer );
+
+       if (!pvid && !devt)
+               return reply_fail("need PVID or device");
+
+       if (!(res.cft = dm_config_create()))
+               return reply_fail("out of memory");
+
+       if (!(res.cft->root = make_text_node(res.cft, "response", "OK", NULL, NULL)))
+               return reply_fail("out of memory");
+
+       lock_pvid_to_pvmeta(s);
+       if (!pvid && devt)
+               pvid = dm_hash_lookup_binary(s->device_to_pvid, &devt, sizeof(devt));
+
+       if (!pvid) {
+               WARN(s, "pv_lookup: could not find device %" PRIu64, devt);
+               unlock_pvid_to_pvmeta(s);
+               dm_config_destroy(res.cft);
+               return reply_unknown("device not found");
+       }
+
+       pv = make_pv_node(s, pvid, res.cft, NULL, res.cft->root);
+       if (!pv) {
+               unlock_pvid_to_pvmeta(s);
+               dm_config_destroy(res.cft);
+               return reply_unknown("PV not found");
+       }
+
+       pv->key = "physical_volume";
+       unlock_pvid_to_pvmeta(s);
+
+       return res;
+}
+
+static response vg_list(lvmetad_state *s, request r)
+{
+       struct dm_config_node *cn, *cn_vgs, *cn_last = NULL;
+       struct dm_hash_node *n;
+       const char *id;
+       const char *name;
+       response res;
+
+       buffer_init( &res.buffer );
+
+       if (!(res.cft = dm_config_create()))
+                goto bad; /* FIXME: better error reporting */
+
+       /* The response field */
+       res.cft->root = cn = dm_config_create_node(res.cft, "response");
+       if (!cn)
+                goto bad; /* FIXME */
+       cn->parent = res.cft->root;
+       if (!(cn->v = dm_config_create_value(res.cft)))
+               goto bad; /* FIXME */
+
+       cn->v->type = DM_CFG_STRING;
+       cn->v->v.str = "OK";
+
+       cn_vgs = cn = cn->sib = dm_config_create_node(res.cft, "volume_groups");
+       if (!cn_vgs)
+               goto bad; /* FIXME */
+
+       cn->parent = res.cft->root;
+       cn->v = NULL;
+       cn->child = NULL;
+
+       lock_vgid_to_metadata(s);
+
+       n = dm_hash_get_first(s->vgid_to_vgname);
+       while (n) {
+               id = dm_hash_get_key(s->vgid_to_vgname, n),
+               name = dm_hash_get_data(s->vgid_to_vgname, n);
+
+               if (!(cn = dm_config_create_node(res.cft, id)))
+                       goto bad; /* FIXME */
+
+               if (cn_last)
+                       cn_last->sib = cn;
+
+               cn->parent = cn_vgs;
+               cn->sib = NULL;
+               cn->v = NULL;
+
+               if (!(cn->child = dm_config_create_node(res.cft, "name")))
+                       goto bad; /* FIXME */
+
+               cn->child->parent = cn;
+               cn->child->sib = 0;
+               if (!(cn->child->v = dm_config_create_value(res.cft)))
+                       goto bad; /* FIXME */
+
+               cn->child->v->type = DM_CFG_STRING;
+               cn->child->v->v.str = name;
+
+               if (!cn_vgs->child)
+                       cn_vgs->child = cn;
+               cn_last = cn;
+
+               n = dm_hash_get_next(s->vgid_to_vgname, n);
+       }
+
+       unlock_vgid_to_metadata(s);
+bad:
+       return res;
+}
+
+static response vg_lookup(lvmetad_state *s, request r)
+{
+       struct dm_config_tree *cft;
+       struct dm_config_node *metadata, *n;
+       response res;
+
+       const char *uuid = daemon_request_str(r, "uuid", NULL);
+       const char *name = daemon_request_str(r, "name", NULL);
+
+       buffer_init( &res.buffer );
+
+       DEBUGLOG(s, "vg_lookup: uuid = %s, name = %s", uuid, name);
+
+       if (!uuid || !name) {
+               lock_vgid_to_metadata(s);
+               if (name && !uuid)
+                       uuid = dm_hash_lookup(s->vgname_to_vgid, name);
+               if (uuid && !name)
+                       name = dm_hash_lookup(s->vgid_to_vgname, uuid);
+               unlock_vgid_to_metadata(s);
+       }
+
+       DEBUGLOG(s, "vg_lookup: updated uuid = %s, name = %s", uuid, name);
+
+       if (!uuid)
+               return reply_unknown("VG not found");
+
+       cft = lock_vg(s, uuid);
+       if (!cft || !cft->root) {
+               unlock_vg(s, uuid);
+               return reply_unknown("UUID not found");
+       }
+
+       metadata = cft->root;
+       if (!(res.cft = dm_config_create()))
+               goto bad;
+
+       /* The response field */
+       if (!(res.cft->root = n = dm_config_create_node(res.cft, "response")))
+               goto bad;
+
+       if (!(n->v = dm_config_create_value(cft)))
+               goto bad;
+
+       n->parent = res.cft->root;
+       n->v->type = DM_CFG_STRING;
+       n->v->v.str = "OK";
+
+       if (!(n = n->sib = dm_config_create_node(res.cft, "name")))
+               goto bad;
+
+       if (!(n->v = dm_config_create_value(res.cft)))
+               goto bad;
+
+       n->parent = res.cft->root;
+       n->v->type = DM_CFG_STRING;
+       n->v->v.str = name;
+
+       /* The metadata section */
+       if (!(n = n->sib = dm_config_clone_node(res.cft, metadata, 1)))
+               goto bad;
+       n->parent = res.cft->root;
+       res.error = 0;
+       unlock_vg(s, uuid);
+
+       update_pv_status(s, res.cft, n, 1); /* FIXME report errors */
+
+       return res;
+bad:
+       unlock_vg(s, uuid);
+       return reply_fail("out of memory");
+}
+
+static int compare_value(struct dm_config_value *a, struct dm_config_value *b)
+{
+       int r = 0;
+
+       if (a->type > b->type)
+               return 1;
+       if (a->type < b->type)
+               return -1;
+
+       switch (a->type) {
+       case DM_CFG_STRING: r = strcmp(a->v.str, b->v.str); break;
+       case DM_CFG_FLOAT: r = (a->v.f == b->v.f) ? 0 : (a->v.f > b->v.f) ? 1 : -1; break;
+       case DM_CFG_INT: r = (a->v.i == b->v.i) ? 0 : (a->v.i > b->v.i) ? 1 : -1; break;
+       case DM_CFG_EMPTY_ARRAY: return 0;
+       }
+
+       if (r == 0 && a->next && b->next)
+               r = compare_value(a->next, b->next);
+       return r;
+}
+
+static int compare_config(struct dm_config_node *a, struct dm_config_node *b)
+{
+       int result = 0;
+       if (a->v && b->v)
+               result = compare_value(a->v, b->v);
+       if (a->v && !b->v)
+               result = 1;
+       if (!a->v && b->v)
+               result = -1;
+       if (a->child && b->child)
+               result = compare_config(a->child, b->child);
+
+       if (result) {
+               // DEBUGLOG("config inequality at %s / %s", a->key, b->key);
+               return result;
+       }
+
+       if (a->sib && b->sib)
+               result = compare_config(a->sib, b->sib);
+       if (a->sib && !b->sib)
+               result = 1;
+       if (!a->sib && b->sib)
+               result = -1;
+
+       return result;
+}
+
+static int vg_remove_if_missing(lvmetad_state *s, const char *vgid);
+
+/* You need to be holding the pvid_to_vgid lock already to call this. */
+static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
+                              const char *vgid, int nuke_empty)
+{
+       struct dm_config_node *pv;
+       struct dm_hash_table *to_check;
+       struct dm_hash_node *n;
+       const char *pvid;
+       const char *vgid_old;
+       const char *check_vgid;
+       int r = 0;
+
+       if (!vgid)
+               return 0;
+
+       if (!(to_check = dm_hash_create(32)))
+               return 0;
+
+       for (pv = pvs(vg->root); pv; pv = pv->sib) {
+               if (!(pvid = dm_config_find_str(pv->child, "id", NULL)))
+                       continue;
+
+               if (nuke_empty &&
+                   (vgid_old = dm_hash_lookup(s->pvid_to_vgid, pvid)) &&
+                   !dm_hash_insert(to_check, vgid_old, (void*) 1))
+                       goto out;
+
+               if (!dm_hash_insert(s->pvid_to_vgid, pvid, (void*) vgid))
+                       goto out;
+
+               DEBUGLOG(s, "moving PV %s to VG %s", pvid, vgid);
+       }
+
+       for (n = dm_hash_get_first(to_check); n;
+            n = dm_hash_get_next(to_check, n)) {
+               check_vgid = dm_hash_get_key(to_check, n);
+               lock_vg(s, check_vgid);
+               vg_remove_if_missing(s, check_vgid);
+               unlock_vg(s, check_vgid);
+       }
+
+       r = 1;
+    out:
+       dm_hash_destroy(to_check);
+
+       return r;
+}
+
+/* A pvid map lock needs to be held if update_pvids = 1. */
+static int remove_metadata(lvmetad_state *s, const char *vgid, int update_pvids)
+{
+       struct dm_config_tree *old;
+       const char *oldname;
+       lock_vgid_to_metadata(s);
+       old = dm_hash_lookup(s->vgid_to_metadata, vgid);
+       oldname = dm_hash_lookup(s->vgid_to_vgname, vgid);
+       unlock_vgid_to_metadata(s);
+
+       if (!old)
+               return 0;
+       assert(oldname);
+
+       if (update_pvids)
+               /* FIXME: What should happen when update fails */
+               update_pvid_to_vgid(s, old, "#orphan", 0);
+       /* need to update what we have since we found a newer version */
+       dm_hash_remove(s->vgid_to_metadata, vgid);
+       dm_hash_remove(s->vgid_to_vgname, vgid);
+       dm_hash_remove(s->vgname_to_vgid, oldname);
+       dm_config_destroy(old);
+       return 1;
+}
+
+/* The VG must be locked. */
+static int vg_remove_if_missing(lvmetad_state *s, const char *vgid)
+{
+       struct dm_config_tree *vg;
+       struct dm_config_node *pv;
+       const char *vgid_check;
+       const char *pvid;
+       int missing = 1;
+
+       if (!vgid)
+               return 0;
+
+       if (!(vg = dm_hash_lookup(s->vgid_to_metadata, vgid)))
+               return 1;
+
+       lock_pvid_to_pvmeta(s);
+       for (pv = pvs(vg->root); pv; pv = pv->sib) {
+               if (!(pvid = dm_config_find_str(pv->child, "id", NULL)))
+                       continue;
+
+               if ((vgid_check = dm_hash_lookup(s->pvid_to_vgid, pvid)) &&
+                   dm_hash_lookup(s->pvid_to_pvmeta, pvid) &&
+                   !strcmp(vgid, vgid_check))
+                       missing = 0; /* at least one PV is around */
+       }
+
+       if (missing) {
+               DEBUGLOG(s, "removing empty VG %s", vgid);
+               remove_metadata(s, vgid, 0);
+       }
+
+       unlock_pvid_to_pvmeta(s);
+
+       return 1;
+}
+
+/* No locks need to be held. The pointers are never used outside of the scope of
+ * this function, so they can be safely destroyed after update_metadata returns
+ * (anything that might have been retained is copied). */
+static int update_metadata(lvmetad_state *s, const char *name, const char *_vgid,
+                          struct dm_config_node *metadata, int64_t *oldseq)
+{
+       struct dm_config_tree *cft = NULL;
+       struct dm_config_tree *old;
+       int retval = 0;
+       int seq;
+       int haveseq = -1;
+       const char *oldname = NULL;
+       const char *vgid;
+       char *cfgname;
+
+       lock_vgid_to_metadata(s);
+       old = dm_hash_lookup(s->vgid_to_metadata, _vgid);
+       lock_vg(s, _vgid);
+       unlock_vgid_to_metadata(s);
+
+       seq = dm_config_find_int(metadata, "metadata/seqno", -1);
+
+       if (old) {
+               haveseq = dm_config_find_int(old->root, "metadata/seqno", -1);
+               oldname = dm_hash_lookup(s->vgid_to_vgname, _vgid);
+               assert(oldname);
+       }
+
+       if (seq < 0)
+               goto out;
+
+       filter_metadata(metadata); /* sanitize */
+
+       if (oldseq) {
+               if (old)
+                       *oldseq = haveseq;
+               else
+                       *oldseq = seq;
+       }
+
+       if (seq == haveseq) {
+               retval = 1;
+               if (compare_config(metadata, old->root))
+                       retval = 0;
+               DEBUGLOG(s, "Not updating metadata for %s at %d (%s)", _vgid, haveseq,
+                     retval ? "ok" : "MISMATCH");
+               if (!retval) {
+                       DEBUGLOG_cft(s, "OLD: ", old->root);
+                       DEBUGLOG_cft(s, "NEW: ", metadata);
+               }
+               goto out;
+       }
+
+       if (seq < haveseq) {
+               DEBUGLOG(s, "Refusing to update metadata for %s (at %d) to %d", _vgid, haveseq, seq);
+               /* TODO: notify the client that their metadata is out of date? */
+               retval = 1;
+               goto out;
+       }
+
+       if (!(cft = dm_config_create()) ||
+           !(cft->root = dm_config_clone_node(cft, metadata, 0))) {
+               ERROR(s, "Out of memory");
+               goto out;
+       }
+
+       vgid = dm_config_find_str(cft->root, "metadata/id", NULL);
+
+       if (!vgid || !name) {
+               DEBUGLOG(s, "Name '%s' or uuid '%s' missing!", name, vgid);
+               goto out;
+       }
+
+       lock_pvid_to_vgid(s);
+
+       if (haveseq >= 0 && haveseq < seq) {
+               INFO(s, "Updating metadata for %s at %d to %d", _vgid, haveseq, seq);
+               /* temporarily orphan all of our PVs */
+               remove_metadata(s, vgid, 1);
+       }
+
+       lock_vgid_to_metadata(s);
+       DEBUGLOG(s, "Mapping %s to %s", vgid, name);
+
+       retval = ((cfgname = dm_pool_strdup(dm_config_memory(cft), name)) &&
+                 dm_hash_insert(s->vgid_to_metadata, vgid, cft) &&
+                 dm_hash_insert(s->vgid_to_vgname, vgid, cfgname) &&
+                 dm_hash_insert(s->vgname_to_vgid, name, (void*) vgid)) ? 1 : 0;
+       unlock_vgid_to_metadata(s);
+
+       if (retval)
+               /* FIXME: What should happen when update fails */
+               retval = update_pvid_to_vgid(s, cft, vgid, 1);
+
+       unlock_pvid_to_vgid(s);
+out:
+       if (!retval && cft)
+               dm_config_destroy(cft);
+       unlock_vg(s, _vgid);
+       return retval;
+}
+
+static response pv_gone(lvmetad_state *s, request r)
+{
+       const char *pvid = daemon_request_str(r, "uuid", NULL);
+       int64_t device = daemon_request_int(r, "device", 0);
+       struct dm_config_tree *pvmeta;
+       char *pvid_old;
+
+       DEBUGLOG(s, "pv_gone: %s / %" PRIu64, pvid, device);
+
+       lock_pvid_to_pvmeta(s);
+       if (!pvid && device > 0)
+               pvid = dm_hash_lookup_binary(s->device_to_pvid, &device, sizeof(device));
+       if (!pvid) {
+               unlock_pvid_to_pvmeta(s);
+               return reply_unknown("device not in cache");
+       }
+
+       DEBUGLOG(s, "pv_gone (updated): %s / %" PRIu64, pvid, device);
+
+       pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid);
+       pvid_old = dm_hash_lookup_binary(s->device_to_pvid, &device, sizeof(device));
+       dm_hash_remove_binary(s->device_to_pvid, &device, sizeof(device));
+       dm_hash_remove(s->pvid_to_pvmeta, pvid);
+       vg_remove_if_missing(s, dm_hash_lookup(s->pvid_to_vgid, pvid));
+       unlock_pvid_to_pvmeta(s);
+
+       if (pvid_old)
+               dm_free(pvid_old);
+
+       if (pvmeta) {
+               dm_config_destroy(pvmeta);
+               return daemon_reply_simple("OK", NULL);
+       } else
+               return reply_unknown("PVID does not exist");
+}
+
+static response pv_clear_all(lvmetad_state *s, request r)
+{
+       DEBUGLOG(s, "pv_clear_all");
+
+       lock_pvid_to_pvmeta(s);
+       lock_vgid_to_metadata(s);
+       lock_pvid_to_vgid(s);
+
+       destroy_metadata_hashes(s);
+       create_metadata_hashes(s);
+
+       unlock_pvid_to_vgid(s);
+       unlock_vgid_to_metadata(s);
+       unlock_pvid_to_pvmeta(s);
+
+       return daemon_reply_simple("OK", NULL);
+}
+
+static response pv_found(lvmetad_state *s, request r)
+{
+       struct dm_config_node *metadata = dm_config_find_node(r.cft->root, "metadata");
+       const char *pvid = daemon_request_str(r, "pvmeta/id", NULL);
+       const char *vgname = daemon_request_str(r, "vgname", NULL);
+       const char *vgid = daemon_request_str(r, "metadata/id", NULL);
+       struct dm_config_node *pvmeta = dm_config_find_node(r.cft->root, "pvmeta");
+       uint64_t device;
+       struct dm_config_tree *cft, *pvmeta_old_dev = NULL, *pvmeta_old_pvid = NULL;
+       char *old;
+       const char *pvid_dup;
+       int complete = 0, orphan = 0;
+       int64_t seqno = -1, seqno_old = -1;
+
+       if (!pvid)
+               return reply_fail("need PV UUID");
+       if (!pvmeta)
+               return reply_fail("need PV metadata");
+
+       if (!dm_config_get_uint64(pvmeta, "pvmeta/device", &device))
+               return reply_fail("need PV device number");
+
+       lock_pvid_to_pvmeta(s);
+
+       if ((old = dm_hash_lookup_binary(s->device_to_pvid, &device, sizeof(device)))) {
+               pvmeta_old_dev = dm_hash_lookup(s->pvid_to_pvmeta, old);
+               dm_hash_remove(s->pvid_to_pvmeta, old);
+       }
+       pvmeta_old_pvid = dm_hash_lookup(s->pvid_to_pvmeta, pvid);
+
+       DEBUGLOG(s, "pv_found %s, vgid = %s, device = %" PRIu64 ", old = %s", pvid, vgid, device, old);
+
+       dm_free(old);
+
+       if (!(cft = dm_config_create()) ||
+           !(cft->root = dm_config_clone_node(cft, pvmeta, 0))) {
+               unlock_pvid_to_pvmeta(s);
+               return reply_fail("out of memory");
+       }
+
+       pvid_dup = dm_strdup(pvid);
+       if (!dm_hash_insert(s->pvid_to_pvmeta, pvid, cft) ||
+           !dm_hash_insert_binary(s->device_to_pvid, &device, sizeof(device), (void*)pvid_dup)) {
+               unlock_pvid_to_pvmeta(s);
+               return reply_fail("out of memory");
+       }
+       if (pvmeta_old_pvid)
+               dm_config_destroy(pvmeta_old_pvid);
+       if (pvmeta_old_dev && pvmeta_old_dev != pvmeta_old_pvid)
+               dm_config_destroy(pvmeta_old_dev);
+
+       unlock_pvid_to_pvmeta(s);
+
+       if (metadata) {
+               if (!vgid)
+                       return reply_fail("need VG UUID");
+               DEBUGLOG(s, "obtained vgid = %s, vgname = %s", vgid, vgname);
+               if (!vgname)
+                       return reply_fail("need VG name");
+               if (daemon_request_int(r, "metadata/seqno", -1) < 0)
+                       return reply_fail("need VG seqno");
+
+               if (!update_metadata(s, vgname, vgid, metadata, &seqno_old))
+                       return reply_fail("metadata update failed");
+       } else {
+               lock_pvid_to_vgid(s);
+               vgid = dm_hash_lookup(s->pvid_to_vgid, pvid);
+               unlock_pvid_to_vgid(s);
+       }
+
+       if (vgid) {
+               if ((cft = lock_vg(s, vgid))) {
+                       complete = update_pv_status(s, cft, cft->root, 0);
+                       seqno = dm_config_find_int(cft->root, "metadata/seqno", -1);
+               } else if (!strcmp(vgid, "#orphan"))
+                       orphan = 1;
+               else {
+                       unlock_vg(s, vgid);
+                       return reply_fail("non-orphan VG without metadata encountered");
+               }
+               unlock_vg(s, vgid);
+       }
+
+       return daemon_reply_simple("OK",
+                                  "status = %s", orphan ? "orphan" :
+                                                    (complete ? "complete" : "partial"),
+                                  "vgid = %s", vgid ? vgid : "#orphan",
+                                  "seqno_before = %"PRId64, seqno_old,
+                                  "seqno_after = %"PRId64, seqno,
+                                  NULL);
+}
+
+static response vg_update(lvmetad_state *s, request r)
+{
+       struct dm_config_node *metadata = dm_config_find_node(r.cft->root, "metadata");
+       const char *vgid = daemon_request_str(r, "metadata/id", NULL);
+       const char *vgname = daemon_request_str(r, "vgname", NULL);
+       if (metadata) {
+               if (!vgid)
+                       return reply_fail("need VG UUID");
+               if (!vgname)
+                       return reply_fail("need VG name");
+               if (daemon_request_int(r, "metadata/seqno", -1) < 0)
+                       return reply_fail("need VG seqno");
+
+               /* TODO defer metadata update here; add a separate vg_commit
+                * call; if client does not commit, die */
+               if (!update_metadata(s, vgname, vgid, metadata, NULL))
+                       return reply_fail("metadata update failed");
+       }
+       return daemon_reply_simple("OK", NULL);
+}
+
+static response vg_remove(lvmetad_state *s, request r)
+{
+       const char *vgid = daemon_request_str(r, "uuid", NULL);
+
+       if (!vgid)
+               return reply_fail("need VG UUID");
+
+       DEBUGLOG(s, "vg_remove: %s", vgid);
+
+       lock_pvid_to_vgid(s);
+       remove_metadata(s, vgid, 1);
+       unlock_pvid_to_vgid(s);
+
+       return daemon_reply_simple("OK", NULL);
+}
+
+static void _dump_cft(struct buffer *buf, struct dm_hash_table *ht, const char *key_addr)
+{
+       struct dm_hash_node *n = dm_hash_get_first(ht);
+       while (n) {
+               struct dm_config_tree *cft = dm_hash_get_data(ht, n);
+               const char *key_backup = cft->root->key;
+               cft->root->key = dm_config_find_str(cft->root, key_addr, "unknown");
+               dm_config_write_node(cft->root, buffer_line, buf);
+               cft->root->key = key_backup;
+               n = dm_hash_get_next(ht, n);
+       }
+}
+
+static void _dump_pairs(struct buffer *buf, struct dm_hash_table *ht, const char *name, int int_key)
+{
+       char *append;
+       struct dm_hash_node *n = dm_hash_get_first(ht);
+
+       buffer_append(buf, name);
+       buffer_append(buf, " {\n");
+
+       while (n) {
+               const char *key = dm_hash_get_key(ht, n),
+                          *val = dm_hash_get_data(ht, n);
+               buffer_append(buf, "    ");
+               if (int_key)
+                       dm_asprintf(&append, "%d = \"%s\"", *(int*)key, val);
+               else
+                       dm_asprintf(&append, "%s = \"%s\"", key, val);
+               if (append)
+                       buffer_append(buf, append);
+               buffer_append(buf, "\n");
+               dm_free(append);
+               n = dm_hash_get_next(ht, n);
+       }
+       buffer_append(buf, "}\n");
+}
+
+static response dump(lvmetad_state *s)
+{
+       response res;
+       struct buffer *b = &res.buffer;
+
+       buffer_init(b);
+
+       /* Lock everything so that we get a consistent dump. */
+
+       lock_vgid_to_metadata(s);
+       lock_pvid_to_pvmeta(s);
+       lock_pvid_to_vgid(s);
+
+       buffer_append(b, "# VG METADATA\n\n");
+       _dump_cft(b, s->vgid_to_metadata, "metadata/id");
+
+       buffer_append(b, "\n# PV METADATA\n\n");
+       _dump_cft(b, s->pvid_to_pvmeta, "pvmeta/id");
+
+       buffer_append(b, "\n# VGID to VGNAME mapping\n\n");
+       _dump_pairs(b, s->vgid_to_vgname, "vgid_to_vgname", 0);
+
+       buffer_append(b, "\n# VGNAME to VGID mapping\n\n");
+       _dump_pairs(b, s->vgname_to_vgid, "vgname_to_vgid", 0);
+
+       buffer_append(b, "\n# PVID to VGID mapping\n\n");
+       _dump_pairs(b, s->pvid_to_vgid, "pvid_to_vgid", 0);
+
+       buffer_append(b, "\n# DEVICE to PVID mapping\n\n");
+       _dump_pairs(b, s->device_to_pvid, "device_to_pvid", 1);
+
+       unlock_pvid_to_vgid(s);
+       unlock_pvid_to_pvmeta(s);
+       unlock_vgid_to_metadata(s);
+
+       return res;
+}
+
+static response handler(daemon_state s, client_handle h, request r)
+{
+       lvmetad_state *state = s.private;
+       const char *rq = daemon_request_str(r, "request", "NONE");
+       const char *token = daemon_request_str(r, "token", "NONE");
+
+       pthread_mutex_lock(&state->token_lock);
+       if (!strcmp(rq, "token_update")) {
+               strncpy(state->token, token, 128);
+               state->token[127] = 0;
+               pthread_mutex_unlock(&state->token_lock);
+               return daemon_reply_simple("OK", NULL);
+       }
+
+       if (strcmp(token, state->token) && strcmp(rq, "dump")) {
+               pthread_mutex_unlock(&state->token_lock);
+               return daemon_reply_simple("token_mismatch",
+                                          "expected = %s", state->token,
+                                          "received = %s", token,
+                                          "reason = %s", "token mismatch", NULL);
+       }
+       pthread_mutex_unlock(&state->token_lock);
+
+       /*
+        * TODO Add a stats call, with transaction count/rate, time since last
+        * update &c.
+        */
+       if (!strcmp(rq, "pv_found"))
+               return pv_found(state, r);
+
+       if (!strcmp(rq, "pv_gone"))
+               return pv_gone(state, r);
+
+       if (!strcmp(rq, "pv_clear_all"))
+               return pv_clear_all(state, r);
+
+       if (!strcmp(rq, "pv_lookup"))
+               return pv_lookup(state, r);
+
+       if (!strcmp(rq, "vg_update"))
+               return vg_update(state, r);
+
+       if (!strcmp(rq, "vg_remove"))
+               return vg_remove(state, r);
+
+       if (!strcmp(rq, "vg_lookup"))
+               return vg_lookup(state, r);
+
+       if (!strcmp(rq, "pv_list"))
+               return pv_list(state, r);
+
+       if (!strcmp(rq, "vg_list"))
+               return vg_list(state, r);
+
+       if (!strcmp(rq, "dump"))
+               return dump(state);
+
+       return reply_fail("request not implemented");
+}
+
+static int init(daemon_state *s)
+{
+       pthread_mutexattr_t rec;
+       lvmetad_state *ls = s->private;
+       ls->log = s->log;
+
+       pthread_mutexattr_init(&rec);
+       pthread_mutexattr_settype(&rec, PTHREAD_MUTEX_RECURSIVE_NP);
+       pthread_mutex_init(&ls->lock.pvid_to_pvmeta, &rec);
+       pthread_mutex_init(&ls->lock.vgid_to_metadata, &rec);
+       pthread_mutex_init(&ls->lock.pvid_to_vgid, NULL);
+       pthread_mutex_init(&ls->lock.vg_lock_map, NULL);
+       pthread_mutex_init(&ls->token_lock, NULL);
+       create_metadata_hashes(ls);
+
+       ls->lock.vg = dm_hash_create(32);
+       ls->token[0] = 0;
+
+       /* Set up stderr logging depending on the -l option. */
+       if (!daemon_log_parse(ls->log, DAEMON_LOG_OUTLET_STDERR, ls->log_config, 1))
+               return 0;
+
+       DEBUGLOG(s, "initialised state: vgid_to_metadata = %p", ls->vgid_to_metadata);
+       if (!ls->pvid_to_vgid || !ls->vgid_to_metadata)
+               return 0;
+
+       /* if (ls->initial_registrations)
+          _process_initial_registrations(ds->initial_registrations); */
+
+       return 1;
+}
+
+static int fini(daemon_state *s)
+{
+       lvmetad_state *ls = s->private;
+       struct dm_hash_node *n;
+
+       DEBUGLOG(s, "fini");
+
+       destroy_metadata_hashes(ls);
+
+       /* Destroy the lock hashes now. */
+       n = dm_hash_get_first(ls->lock.vg);
+       while (n) {
+               pthread_mutex_destroy(dm_hash_get_data(ls->lock.vg, n));
+               free(dm_hash_get_data(ls->lock.vg, n));
+               n = dm_hash_get_next(ls->lock.vg, n);
+       }
+
+       dm_hash_destroy(ls->lock.vg);
+       return 1;
+}
+
+static void usage(char *prog, FILE *file)
+{
+       fprintf(file, "Usage:\n"
+               "%s [-V] [-h] [-f] [-l {all|wire|debug}] [-s path]\n\n"
+               "   -V       Show version of lvmetad\n"
+               "   -h       Show this help information\n"
+               "   -f       Don't fork, run in the foreground\n"
+               "   -l       Logging message level (-l {all|wire|debug})\n"
+               "   -s       Set path to the socket to listen on\n\n", prog);
+}
+
+int main(int argc, char *argv[])
+{
+       signed char opt;
+       daemon_state s = { .private = NULL };
+       lvmetad_state ls;
+       int _socket_override = 1;
+
+       s.name = "lvmetad";
+       s.private = &ls;
+       s.daemon_init = init;
+       s.daemon_fini = fini;
+       s.handler = handler;
+       s.socket_path = getenv("LVM_LVMETAD_SOCKET");
+       if (!s.socket_path) {
+               _socket_override = 0;
+               s.socket_path = DEFAULT_RUN_DIR "/lvmetad.socket";
+       }
+       s.pidfile = LVMETAD_PIDFILE;
+       s.protocol = "lvmetad";
+       s.protocol_version = 1;
+       ls.log_config = "";
+
+       // use getopt_long
+       while ((opt = getopt(argc, argv, "?fhVl:s:")) != EOF) {
+               switch (opt) {
+               case 'h':
+                       usage(argv[0], stdout);
+                       exit(0);
+               case '?':
+                       usage(argv[0], stderr);
+                       exit(0);
+               case 'f':
+                       s.foreground = 1;
+                       break;
+               case 'l':
+                       ls.log_config = optarg;
+                       break;
+               case 's': // --socket
+                       s.socket_path = optarg;
+                       _socket_override = 1;
+                       break;
+               case 'V':
+                       printf("lvmetad version: " LVM_VERSION "\n");
+                       exit(1);
+               }
+       }
+
+       if (s.foreground) {
+               if (!_socket_override) {
+                       fprintf(stderr, "A socket path (-s) is required in foreground mode.");
+                       exit(2);
+               } else {
+                       s.pidfile = NULL;
+               }
+       }
+
+       daemon_start(s);
+       return 0;
+}
diff --git a/daemons/lvmetad/test.sh b/daemons/lvmetad/test.sh
new file mode 100755 (executable)
index 0000000..f937562
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+export LD_LIBRARY_PATH="$1"
+
+test -n "$2" && {
+    rm -f /var/run/lvmetad.{socket,pid}
+    chmod +rx lvmetad
+    valgrind ./lvmetad -f &
+    PID=$!
+    sleep 1
+    ./testclient
+    kill $PID
+    exit 0
+}
+
+sudo ./test.sh "$1" .
diff --git a/daemons/lvmetad/testclient.c b/daemons/lvmetad/testclient.c
new file mode 100644 (file)
index 0000000..c4cf7c5
--- /dev/null
@@ -0,0 +1,127 @@
+#include "lvmetad-client.h"
+#include "label.h"
+#include "lvmcache.h"
+#include "metadata.h"
+
+const char *uuid1 = "abcd-efgh";
+const char *uuid2 = "bbcd-efgh";
+const char *vgid = "yada-yada";
+const char *uuid3 = "cbcd-efgh";
+
+const char *metadata2 = "{\n"
+       "id = \"yada-yada\"\n"
+       "seqno = 15\n"
+       "status = [\"READ\", \"WRITE\"]\n"
+       "flags = []\n"
+       "extent_size = 8192\n"
+       "physical_volumes {\n"
+       "    pv0 {\n"
+       "        id = \"abcd-efgh\"\n"
+       "    }\n"
+       "    pv1 {\n"
+       "        id = \"bbcd-efgh\"\n"
+       "    }\n"
+       "    pv2 {\n"
+       "        id = \"cbcd-efgh\"\n"
+       "    }\n"
+       "}\n"
+       "}\n";
+
+void _handle_reply(daemon_reply reply) {
+       const char *repl = daemon_reply_str(reply, "response", NULL);
+       const char *status = daemon_reply_str(reply, "status", NULL);
+       const char *vgid = daemon_reply_str(reply, "vgid", NULL);
+
+       fprintf(stderr, "[C] REPLY: %s\n", repl);
+       if (!strcmp(repl, "failed"))
+               fprintf(stderr, "[C] REASON: %s\n", daemon_reply_str(reply, "reason", "unknown"));
+       if (vgid)
+               fprintf(stderr, "[C] VGID: %s\n", vgid);
+       if (status)
+               fprintf(stderr, "[C] STATUS: %s\n", status);
+       daemon_reply_destroy(reply);
+}
+
+void _pv_add(daemon_handle h, const char *uuid, const char *metadata)
+{
+       daemon_reply reply = daemon_send_simple(h, "pv_add", "uuid = %s", uuid,
+                                                            "metadata = %b", metadata,
+                                                            NULL);
+       _handle_reply(reply);
+}
+
+int scan(daemon_handle h, char *fn) {
+       struct device *dev = dev_cache_get(fn, NULL);
+
+       struct label *label;
+       if (!label_read(dev, &label, 0)) {
+               fprintf(stderr, "[C] no label found on %s\n", fn);
+               return;
+       }
+
+       char uuid[64];
+       id_write_format(dev->pvid, uuid, 64);
+       fprintf(stderr, "[C] found PV: %s\n", uuid);
+       struct lvmcache_info *info = (struct lvmcache_info *) label->info;
+       struct physical_volume pv = { 0, };
+
+       if (!(info->fmt->ops->pv_read(info->fmt, dev_name(dev), &pv, 0))) {
+               fprintf(stderr, "[C] Failed to read PV %s", dev_name(dev));
+               return;
+       }
+
+       struct format_instance_ctx fic;
+       struct format_instance *fid = info->fmt->ops->create_instance(info->fmt, &fic);
+       struct metadata_area *mda;
+       struct volume_group *vg = NULL;
+       dm_list_iterate_items(mda, &info->mdas) {
+               struct volume_group *this = mda->ops->vg_read(fid, "", mda);
+               if (this && !vg || this->seqno > vg->seqno)
+                       vg = this;
+       }
+       if (vg) {
+               char *buf = NULL;
+               /* TODO. This is not entirely correct, since export_vg_to_buffer
+                * adds trailing garbage to the buffer. We may need to use
+                * export_vg_to_config_tree and format the buffer ourselves. It
+                * does, however, work for now, since the garbage is well
+                * formatted and has no conflicting keys with the rest of the
+                * request.  */
+               export_vg_to_buffer(vg, &buf);
+               daemon_reply reply =
+                       daemon_send_simple(h, "pv_add", "uuid = %s", uuid,
+                                             "metadata = %b", strchr(buf, '{'),
+                                             NULL);
+               _handle_reply(reply);
+       }
+}
+
+void _dump_vg(daemon_handle h, const char *uuid)
+{
+       daemon_reply reply = daemon_send_simple(h, "vg_by_uuid", "uuid = %s", uuid, NULL);
+       fprintf(stderr, "[C] reply buffer: %s\n", reply.buffer);
+       daemon_reply_destroy(reply);
+}
+
+int main(int argc, char **argv) {
+       daemon_handle h = lvmetad_open();
+
+       if (argc > 1) {
+               int i;
+               struct cmd_context *cmd = create_toolcontext(0, NULL, 0, 0);
+               for (i = 1; i < argc; ++i) {
+                       const char *uuid = NULL;
+                       scan(h, argv[i]);
+               }
+               destroy_toolcontext(cmd);
+               return 0;
+       }
+
+       _pv_add(h, uuid1, NULL);
+       _pv_add(h, uuid2, metadata2);
+       _dump_vg(h, vgid);
+       _pv_add(h, uuid3, NULL);
+
+       daemon_close(h);
+       return 0;
+}
index 8504f5dc0a47e1a22e34bdc908e72c6385f7abca..f7344bbbeb209fba30c283410d70f05afb76940d 100644 (file)
@@ -6,6 +6,9 @@
 #
 # To put this file in a different directory and override @DEFAULT_SYS_DIR@ set
 # the environment variable LVM_SYSTEM_DIR before running the tools.
+#
+# N.B. Take care that each setting only appears once if uncommenting
+# example settings in this file.
 
 
 # This section allows you to configure which block devices should
@@ -19,6 +22,16 @@ devices {
     # to use with LVM2.
     scan = [ "/dev" ]
 
+    # If set, the cache of block device nodes with all associated symlinks
+    # will be constructed out of the existing udev database content.
+    # This avoids using and opening any inapplicable non-block devices or
+    # subdirectories found in the device directory. This setting is applied
+    # to udev-managed device directory only, other directories will be scanned
+    # fully. LVM2 needs to be compiled with udev support for this setting to
+    # take effect. N.B. Any device node or symlink not managed by udev in
+    # udev directory will be ignored with this setting on.
+    obtain_device_list_from_udev = 1
+
     # If several entries in the scanned directories correspond to the
     # same block device and the tools need to display a name for device,
     # all the pathnames are matched against each item in the following
@@ -38,9 +51,11 @@ devices {
 
     # Be careful if there there are symbolic links or multiple filesystem 
     # entries for the same device as each name is checked separately against
-    # the list of patterns.  The effect is that if any name matches any 'a'
-    # pattern, the device is accepted; otherwise if any name matches any 'r'
-    # pattern it is rejected; otherwise it is accepted.
+    # the list of patterns.  The effect is that if the first pattern in the 
+    # list to match a name is an 'a' pattern for any of the names, the device
+    # is accepted; otherwise if the first pattern in the list to match a name
+    # is an 'r' pattern for any of the names it is rejected; otherwise it is
+    # accepted.
 
     # Don't have more than one filter line active at once: only one gets used.
 
@@ -64,6 +79,14 @@ devices {
     # Use anchors if you want to be really specific
     # filter = [ "a|^/dev/hda8$|", "r/.*/" ]
 
+    # Since "filter" is often overriden from command line, it is not suitable
+    # for system-wide device filtering (udev rules, lvmetad). To hide devices
+    # from LVM-specific udev processing and/or from lvmetad, you need to set
+    # global_filter. The syntax is the same as for normal "filter"
+    # above. Devices that fail the global_filter are not even opened by LVM.
+
+    # global_filter = []
+
     # The results of the filtering are cached on disk to avoid
     # rescanning dud devices (which can take a very long time).
     # By default this cache is stored in the @DEFAULT_SYS_DIR@/@DEFAULT_CACHE_SUBDIR@ directory
@@ -71,6 +94,9 @@ devices {
     # It is safe to delete the contents: the tools regenerate it.
     # (The old setting 'cache' is still respected if neither of
     # these new ones is present.)
+    # N.B. If obtain_device_list_from_udev is set to 1 the list of
+    # devices is instead obtained from udev and any existing .cache
+    # file is removed.
     cache_dir = "@DEFAULT_SYS_DIR@/@DEFAULT_CACHE_SUBDIR@"
     cache_file_prefix = ""
 
@@ -88,6 +114,11 @@ devices {
     # 1 enables; 0 disables.
     sysfs_scan = 1
 
+    # By default, LVM2 will ignore devices used as component paths
+    # of device-mapper multipath devices.
+    # 1 enables; 0 disables.
+    multipath_component_detection = 1
+
     # By default, LVM2 will ignore devices used as components of
     # software RAID (md) devices by looking for md superblocks.
     # 1 enables; 0 disables.
@@ -144,26 +175,64 @@ devices {
 
     # Allow use of pvcreate --uuid without requiring --restorefile.
     require_restorefile_with_uuid = 1
+
+    # Minimum size (in KB) of block devices which can be used as PVs.
+    # In a clustered environment all nodes must use the same value.
+    # Any value smaller than 512KB is ignored.
+
+    # Ignore devices smaller than 2MB such as floppy drives.
+    pv_min_size = 2048
+
+    # The original built-in setting was 512 up to and including version 2.02.84.
+    # pv_min_size = 512
+
+    # Issue discards to a logical volumes's underlying physical volume(s) when
+    # the logical volume is no longer using the physical volumes' space (e.g.
+    # lvremove, lvreduce, etc).  Discards inform the storage that a region is
+    # no longer in use.  Storage that supports discards advertise the protocol
+    # specific way discards should be issued by the kernel (TRIM, UNMAP, or
+    # WRITE SAME with UNMAP bit set).  Not all storage will support or benefit
+    # from discards but SSDs and thinly provisioned LUNs generally do.  If set
+    # to 1, discards will only be issued if both the storage and kernel provide
+    # support.
+    # 1 enables; 0 disables.
+    issue_discards = 0
 }
 
 # This section allows you to configure the way in which LVM selects
 # free space for its Logical Volumes.
-#allocation {
-#    When searching for free space to extend an LV, the "cling"
-#    allocation policy will choose space on the same PVs as the last
-#    segment of the existing LV.  If there is insufficient space and a
-#    list of tags is defined here, it will check whether any of them are
-#    attached to the PVs concerned and then seek to match those PV tags
-#    between existing extents and new extents.
-#    Use the special tag "@*" as a wildcard to match any PV tag.
-#    
-#    Example: LVs are mirrored between two sites within a single VG.
-#    PVs are tagged with either @site1 or @site2 to indicate where
-#    they are situated.
-#
-#    cling_tag_list = [ "@site1", "@site2" ]
-#    cling_tag_list = [ "@*" ]
-#}
+allocation {
+
+    # When searching for free space to extend an LV, the "cling"
+    # allocation policy will choose space on the same PVs as the last
+    # segment of the existing LV.  If there is insufficient space and a
+    # list of tags is defined here, it will check whether any of them are
+    # attached to the PVs concerned and then seek to match those PV tags
+    # between existing extents and new extents.
+    # Use the special tag "@*" as a wildcard to match any PV tag.
+    # Example: LVs are mirrored between two sites within a single VG.
+    # PVs are tagged with either @site1 or @site2 to indicate where
+    # they are situated.
+
+    # cling_tag_list = [ "@site1", "@site2" ]
+    # cling_tag_list = [ "@*" ]
+
+    # Changes made in version 2.02.85 extended the reach of the 'cling'
+    # policies to detect more situations where data can be grouped
+    # onto the same disks.  Set this to 0 to revert to the previous
+    # algorithm.
+    maximise_cling = 1
+
+    # Set to 1 to guarantee that mirror logs will always be placed on 
+    # different PVs from the mirror images.  This was the default
+    # until version 2.02.85.
+    mirror_logs_require_separate_pvs = 0
+
+    # Set to 1 to guarantee that thin pool metadata will always
+    # be placed on different PVs from the pool data.
+    thin_pool_metadata_require_separate_pvs = 0
+}
 
 # This section that allows you to configure the nature of the
 # information that LVM2 reports.
@@ -173,6 +242,17 @@ log {
     # There are three levels of verbosity, 3 being the most verbose.
     verbose = 0
 
+    # Set to 1 to suppress all non-essential messages from stdout.
+    # This has the same effect as -qq.
+    # When this is set, the following commands still produce output:
+    # dumpconfig, lvdisplay, lvmdiskscan, lvs, pvck, pvdisplay, 
+    # pvs, version, vgcfgrestore -l, vgdisplay, vgs.
+    # Non-essential messages are shifted from log level 4 to log level 5
+    # for syslog and lvm2_log_fn purposes.
+    # Any 'yes' or 'no' questions not overridden by other arguments
+    # are suppressed and default to 'no'.
+    silent = 0
+
     # Should we send log messages through syslog?
     # 1 is yes; 0 is no.
     syslog = 1
@@ -354,15 +434,88 @@ global {
     # encountered the internal error. Please only enable for debugging.
     abort_on_internal_errors = 0
 
+    # Check whether CRC is matching when parsed VG is used multiple times.
+    # This is useful to catch unexpected internal cached volume group
+    # structure modification. Please only enable for debugging.
+    detect_internal_vg_cache_corruption = 0
+
     # If set to 1, no operations that change on-disk metadata will be permitted.
     # Additionally, read-only commands that encounter metadata in need of repair
     # will still be allowed to proceed exactly as if the repair had been 
     # performed (except for the unchanged vg_seqno).
     # Inappropriate use could mess up your system, so seek advice first!
     metadata_read_only = 0
+
+    # 'mirror_segtype_default' defines which segtype will be used when the
+    # shorthand '-m' option is used for mirroring.  The possible options are:
+    #
+    # "mirror" - The original RAID1 implementation provided by LVM2/DM.  It is
+    #           characterized by a flexible log solution (core, disk, mirrored)
+    #           and by the necessity to block I/O while reconfiguring in the
+    #           event of a failure.
+    #
+    #           There is an inherent race in the dmeventd failure handling
+    #           logic with snapshots of devices using this type of RAID1 that
+    #           in the worst case could cause a deadlock.
+    #             Ref: https://bugzilla.redhat.com/show_bug.cgi?id=817130#c10
+    #
+    # "raid1"  - This implementation leverages MD's RAID1 personality through
+    #           device-mapper.  It is characterized by a lack of log options.
+    #           (A log is always allocated for every device and they are placed
+    #           on the same device as the image - no separate devices are
+    #           required.)  This mirror implementation does not require I/O
+    #           to be blocked in the kernel in the event of a failure.
+    #           This mirror implementation is not cluster-aware and cannot be
+    #           used in a shared (active/active) fashion in a cluster.
+    #
+    # Specify the '--type <mirror|raid1>' option to override this default
+    # setting.
+    mirror_segtype_default = "mirror"
+
+    # The default format for displaying LV names in lvdisplay was changed 
+    # in version 2.02.89 to show the LV name and path separately.
+    # Previously this was always shown as /dev/vgname/lvname even when that
+    # was never a valid path in the /dev filesystem.
+    # Set to 1 to reinstate the previous format.
+    #
+    # lvdisplay_shows_full_device_path = 0
+
+    # Whether to use (trust) a running instance of lvmetad. If this is set to
+    # 0, all commands fall back to the usual scanning mechanisms. When set to 1
+    # *and* when lvmetad is running (it is not auto-started), the volume group
+    # metadata and PV state flags are obtained from the lvmetad instance and no
+    # scanning is done by the individual commands. In a setup with lvmetad,
+    # lvmetad udev rules *must* be set up for LVM to work correctly. Without
+    # proper udev rules, all changes in block device configuration will be
+    # *ignored* until a manual 'pvscan --cache' is performed.
+    #
+    # If lvmetad has been running while use_lvmetad was 0, it MUST be stopped
+    # before changing use_lvmetad to 1 and started again afterwards.
+    use_lvmetad = 0
+
+    # Full path of the utility called to check that a thin metadata device
+    # is in a state that allows it to be used.
+    # Each time a thin pool needs to be activated or after it is deactivated
+    # this utility is executed. The activation will only proceed if the utility
+    # has an exit status of 0.
+    # Set to "" to skip this check.  (Not recommended.)
+    # The thin tools are available as part of the device-mapper-persistent-data
+    # package from https://github.com/jthornber/thin-provisioning-tools.
+    #
+    thin_check_executable = "@THIN_CHECK_CMD@"
+
+    # String with options passed with thin_check command. By default,
+    # option '-q' is for quiet output.
+    thin_check_options = [ "-q" ]
 }
 
 activation {
+    # Set to 1 to perform internal checks on the operations issued to
+    # libdevmapper.  Useful for debugging problems with activation.
+    # Some of the checks may be expensive, so it's best to use this
+    # only when there seems to be a problem.
+    checks = 0
+
     # Set to 0 to disable udev synchronisation (if compiled into the binaries).
     # Processes will not wait for notification from udev.
     # They will continue irrespective of any possible udev processing
@@ -380,6 +533,17 @@ activation {
     # while any logical volumes are active.
     udev_rules = 1
 
+    # Set to 1 for LVM2 to verify operations performed by udev. This turns on
+    # additional checks (and if necessary, repairs) on entries in the device
+    # directory after udev has completed processing its events. 
+    # Useful for diagnosing problems with LVM2/udev interactions.
+    verify_udev_operations = 0
+
+    # If set to 1 and if deactivation of an LV fails, perhaps because
+    # a process run from a quick udev rule temporarily opened the device,
+    # retry the operation for a few seconds before failing.
+    retry_deactivation = 1
+
     # How to fill in missing stripes if activating an incomplete volume.
     # Using "error" will make inaccessible parts of the device return
     # I/O errors on access.  You can instead use a device path, in which 
@@ -388,8 +552,14 @@ activation {
     # or snapshotted volumes is likely to result in data corruption.
     missing_stripe_filler = "error"
 
+    # The linear target is an optimised version of the striped target
+    # that only handles a single stripe.  Set this to 0 to disable this
+    # optimisation and always use the striped target.
+    use_linear_target = 1
+
     # How much stack (in KB) to reserve for use while devices suspended
-    reserved_stack = 256
+    # Prior to version 2.02.89 this used to be set to 256KB
+    reserved_stack = 64
 
     # How much memory (in KB) to reserve for use while devices suspended
     reserved_memory = 8192
@@ -405,6 +575,25 @@ activation {
     #
     # volume_list = [ "vg1", "vg2/lvol1", "@tag1", "@*" ]
 
+    # If auto_activation_volume_list is defined, each LV that is to be
+    # activated is checked against the list while using the autoactivation
+    # option (--activate ay/-a ay), and if it matches, it is activated.
+    #   "vgname" and "vgname/lvname" are matched exactly.
+    #   "@tag" matches any tag set in the LV or VG.
+    #   "@*" matches if any tag defined on the host is also set in the LV or VG
+    #
+    # auto_activation_volume_list = [ "vg1", "vg2/lvol1", "@tag1", "@*" ]
+
+    # If read_only_volume_list is defined, each LV that is to be activated 
+    # is checked against the list, and if it matches, it as activated
+    # in read-only mode.  (This overrides '--permission rw' stored in the
+    # metadata.)
+    #   "vgname" and "vgname/lvname" are matched exactly.
+    #   "@tag" matches any tag set in the LV or VG.
+    #   "@*" matches if any tag defined on the host is also set in the LV or VG
+    #
+    # read_only_volume_list = [ "vg1", "vg2/lvol1", "@tag1", "@*" ]
+
     # Size (in KB) of each copy operation when mirroring
     mirror_region_size = 512
 
@@ -414,9 +603,31 @@ activation {
     # "auto" - Use default value chosen by kernel.
     readahead = "auto"
 
+    # 'raid_fault_policy' defines how a device failure in a RAID logical
+    # volume is handled.  This includes logical volumes that have the following
+    # segment types: raid1, raid4, raid5*, and raid6*.
+    #
+    # In the event of a failure, the following policies will determine what
+    # actions are performed during the automated response to failures (when
+    # dmeventd is monitoring the RAID logical volume) and when 'lvconvert' is
+    # called manually with the options '--repair' and '--use-policies'.
+    #
+    # "warn"   - Use the system log to warn the user that a device in the RAID
+    #            logical volume has failed.  It is left to the user to run
+    #            'lvconvert --repair' manually to remove or replace the failed
+    #            device.  As long as the number of failed devices does not
+    #            exceed the redundancy of the logical volume (1 device for
+    #            raid4/5, 2 for raid6, etc) the logical volume will remain
+    #            usable.
+    #
+    # "allocate" - Attempt to use any extra physical volumes in the volume
+    #            group as spares and replace faulty devices.
+    #
+    raid_fault_policy = "warn"
+
     # 'mirror_image_fault_policy' and 'mirror_log_fault_policy' define
-    # how a device failure affecting a mirror is handled.
-    # A mirror is composed of mirror images (copies) and a log.
+    # how a device failure affecting a mirror (of "mirror" segment type) is
+    # handled.  A mirror is composed of mirror images (copies) and a log.
     # A disk log ensures that a mirror does not need to be re-synced
     # (all copies made the same) every time a machine reboots or crashes.
     #
@@ -473,6 +684,25 @@ activation {
     snapshot_autoextend_threshold = 100
     snapshot_autoextend_percent = 20
 
+    # 'thin_pool_autoextend_threshold' and 'thin_pool_autoextend_percent' define
+    # how to handle automatic pool extension. The former defines when the
+    # pool should be extended: when its space usage exceeds this many
+    # percent. The latter defines how much extra space should be allocated for
+    # the pool, in percent of its current size.
+    #
+    # For example, if you set thin_pool_autoextend_threshold to 70 and
+    # thin_pool_autoextend_percent to 20, whenever a pool exceeds 70% usage,
+    # it will be extended by another 20%. For a 1G pool, using up 700M will
+    # trigger a resize to 1.2G. When the usage exceeds 840M, the pool will
+    # be extended to 1.44G, and so on.
+    #
+    # Setting thin_pool_autoextend_threshold to 100 disables automatic
+    # extensions. The minimum value is 50 (A setting below 50 will be treated
+    # as 50).
+
+    thin_pool_autoextend_threshold = 100
+    thin_pool_autoextend_percent = 20
+
     # While activating devices, I/O to devices being (re)configured is
     # suspended, and as a precaution against deadlocks, LVM2 needs to pin
     # any memory it is using so it is not paged out.  Groups of pages that
@@ -571,6 +801,15 @@ dmeventd {
 
     snapshot_library = "libdevmapper-event-lvm2snapshot.so"
 
+    # thin_library is the library used when monitoring a thin device.
+    #
+    # "libdevmapper-event-lvm2thin.so" monitors the filling of
+    # pool and emits a warning through syslog when the use of
+    # the pool exceeds 80%. The warning is repeated when 85%, 90% and
+    # 95% of the pool is filled.
+
+    thin_library = "libdevmapper-event-lvm2thin.so"
+
     # Full path of the dmeventd binary.
     #
     # executable = "@DMEVENTD_PATH@"
diff --git a/doc/kernel/crypt.txt b/doc/kernel/crypt.txt
new file mode 100644 (file)
index 0000000..2c656ae
--- /dev/null
@@ -0,0 +1,76 @@
+dm-crypt
+=========
+
+Device-Mapper's "crypt" target provides transparent encryption of block devices
+using the kernel crypto API.
+
+Parameters: <cipher> <key> <iv_offset> <device path> \
+             <offset> [<#opt_params> <opt_params>]
+
+<cipher>
+    Encryption cipher and an optional IV generation mode.
+    (In format cipher[:keycount]-chainmode-ivopts:ivmode).
+    Examples:
+       des
+       aes-cbc-essiv:sha256
+       twofish-ecb
+
+    /proc/crypto contains supported crypto modes
+
+<key>
+    Key used for encryption. It is encoded as a hexadecimal number.
+    You can only use key sizes that are valid for the selected cipher.
+
+<keycount>
+    Multi-key compatibility mode. You can define <keycount> keys and
+    then sectors are encrypted according to their offsets (sector 0 uses key0;
+    sector 1 uses key1 etc.).  <keycount> must be a power of two.
+
+<iv_offset>
+    The IV offset is a sector count that is added to the sector number
+    before creating the IV.
+
+<device path>
+    This is the device that is going to be used as backend and contains the
+    encrypted data.  You can specify it as a path like /dev/xxx or a device
+    number <major>:<minor>.
+
+<offset>
+    Starting sector within the device where the encrypted data begins.
+
+<#opt_params>
+    Number of optional parameters. If there are no optional parameters,
+    the optional paramaters section can be skipped or #opt_params can be zero.
+    Otherwise #opt_params is the number of following arguments.
+
+    Example of optional parameters section:
+        1 allow_discards
+
+allow_discards
+    Block discard requests (a.k.a. TRIM) are passed through the crypt device.
+    The default is to ignore discard requests.
+
+    WARNING: Assess the specific security risks carefully before enabling this
+    option.  For example, allowing discards on encrypted devices may lead to
+    the leak of information about the ciphertext device (filesystem type,
+    used space etc.) if the discarded blocks can be located easily on the
+    device later.
+
+Example scripts
+===============
+LUKS (Linux Unified Key Setup) is now the preferred way to set up disk
+encryption with dm-crypt using the 'cryptsetup' utility, see
+http://code.google.com/p/cryptsetup/
+
+[[
+#!/bin/sh
+# Create a crypt device using dmsetup
+dmsetup create crypt1 --table "0 `blockdev --getsize $1` crypt aes-cbc-essiv:sha256 babebabebabebabebabebabebabebabe 0 $1 0"
+]]
+
+[[
+#!/bin/sh
+# Create a crypt device using cryptsetup and LUKS header with default cipher
+cryptsetup luksFormat $1
+cryptsetup luksOpen $1 crypt1
+]]
diff --git a/doc/kernel/delay.txt b/doc/kernel/delay.txt
new file mode 100644 (file)
index 0000000..15adc55
--- /dev/null
@@ -0,0 +1,26 @@
+dm-delay
+========
+
+Device-Mapper's "delay" target delays reads and/or writes
+and maps them to different devices.
+
+Parameters:
+    <device> <offset> <delay> [<write_device> <write_offset> <write_delay>]
+
+With separate write parameters, the first set is only used for reads.
+Delays are specified in milliseconds.
+
+Example scripts
+===============
+[[
+#!/bin/sh
+# Create device delaying rw operation for 500ms
+echo "0 `blockdev --getsize $1` delay $1 0 500" | dmsetup create delayed
+]]
+
+[[
+#!/bin/sh
+# Create device delaying only write operation for 500ms and
+# splitting reads and writes to different devices $1 $2
+echo "0 `blockdev --getsize $1` delay $1 0 0 $2 0 500" | dmsetup create delayed
+]]
diff --git a/doc/kernel/flakey.txt b/doc/kernel/flakey.txt
new file mode 100644 (file)
index 0000000..6ff5c23
--- /dev/null
@@ -0,0 +1,53 @@
+dm-flakey
+=========
+
+This target is the same as the linear target except that it exhibits
+unreliable behaviour periodically.  It's been found useful in simulating
+failing devices for testing purposes.
+
+Starting from the time the table is loaded, the device is available for
+<up interval> seconds, then exhibits unreliable behaviour for <down
+interval> seconds, and then this cycle repeats.
+
+Also, consider using this in combination with the dm-delay target too,
+which can delay reads and writes and/or send them to different
+underlying devices.
+
+Table parameters
+----------------
+  <dev path> <offset> <up interval> <down interval> \
+    [<num_features> [<feature arguments>]]
+
+Mandatory parameters:
+    <dev path>: Full pathname to the underlying block-device, or a
+                "major:minor" device-number.
+    <offset>: Starting sector within the device.
+    <up interval>: Number of seconds device is available.
+    <down interval>: Number of seconds device returns errors.
+
+Optional feature parameters:
+  If no feature parameters are present, during the periods of
+  unreliability, all I/O returns errors.
+
+  drop_writes:
+       All write I/O is silently ignored.
+       Read I/O is handled correctly.
+
+  corrupt_bio_byte <Nth_byte> <direction> <value> <flags>:
+       During <down interval>, replace <Nth_byte> of the data of
+       each matching bio with <value>.
+
+    <Nth_byte>: The offset of the byte to replace.
+               Counting starts at 1, to replace the first byte.
+    <direction>: Either 'r' to corrupt reads or 'w' to corrupt writes.
+                'w' is incompatible with drop_writes.
+    <value>: The value (from 0-255) to write.
+    <flags>: Perform the replacement only if bio->bi_rw has all the
+            selected flags set.
+
+Examples:
+  corrupt_bio_byte 32 r 1 0
+       - replaces the 32nd byte of READ bios with the value 1
+
+  corrupt_bio_byte 224 w 0 32
+       - replaces the 224th byte of REQ_META (=32) bios with the value 0
diff --git a/doc/kernel/io.txt b/doc/kernel/io.txt
new file mode 100644 (file)
index 0000000..3b5d9a5
--- /dev/null
@@ -0,0 +1,75 @@
+dm-io
+=====
+
+Dm-io provides synchronous and asynchronous I/O services. There are three
+types of I/O services available, and each type has a sync and an async
+version.
+
+The user must set up an io_region structure to describe the desired location
+of the I/O. Each io_region indicates a block-device along with the starting
+sector and size of the region.
+
+   struct io_region {
+      struct block_device *bdev;
+      sector_t sector;
+      sector_t count;
+   };
+
+Dm-io can read from one io_region or write to one or more io_regions. Writes
+to multiple regions are specified by an array of io_region structures.
+
+The first I/O service type takes a list of memory pages as the data buffer for
+the I/O, along with an offset into the first page.
+
+   struct page_list {
+      struct page_list *next;
+      struct page *page;
+   };
+
+   int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw,
+                  struct page_list *pl, unsigned int offset,
+                  unsigned long *error_bits);
+   int dm_io_async(unsigned int num_regions, struct io_region *where, int rw,
+                   struct page_list *pl, unsigned int offset,
+                   io_notify_fn fn, void *context);
+
+The second I/O service type takes an array of bio vectors as the data buffer
+for the I/O. This service can be handy if the caller has a pre-assembled bio,
+but wants to direct different portions of the bio to different devices.
+
+   int dm_io_sync_bvec(unsigned int num_regions, struct io_region *where,
+                       int rw, struct bio_vec *bvec,
+                       unsigned long *error_bits);
+   int dm_io_async_bvec(unsigned int num_regions, struct io_region *where,
+                        int rw, struct bio_vec *bvec,
+                        io_notify_fn fn, void *context);
+
+The third I/O service type takes a pointer to a vmalloc'd memory buffer as the
+data buffer for the I/O. This service can be handy if the caller needs to do
+I/O to a large region but doesn't want to allocate a large number of individual
+memory pages.
+
+   int dm_io_sync_vm(unsigned int num_regions, struct io_region *where, int rw,
+                     void *data, unsigned long *error_bits);
+   int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw,
+                      void *data, io_notify_fn fn, void *context);
+
+Callers of the asynchronous I/O services must include the name of a completion
+callback routine and a pointer to some context data for the I/O.
+
+   typedef void (*io_notify_fn)(unsigned long error, void *context);
+
+The "error" parameter in this callback, as well as the "*error" parameter in
+all of the synchronous versions, is a bitset (instead of a simple error value).
+In the case of an write-I/O to multiple regions, this bitset allows dm-io to
+indicate success or failure on each individual region.
+
+Before using any of the dm-io services, the user should call dm_io_get()
+and specify the number of pages they expect to perform I/O on concurrently.
+Dm-io will attempt to resize its mempool to make sure enough pages are
+always available in order to avoid unnecessary waiting while performing I/O.
+
+When the user is finished using the dm-io services, they should call
+dm_io_put() and specify the same number of pages that were given on the
+dm_io_get() call.
+
diff --git a/doc/kernel/kcopyd.txt b/doc/kernel/kcopyd.txt
new file mode 100644 (file)
index 0000000..820382c
--- /dev/null
@@ -0,0 +1,47 @@
+kcopyd
+======
+
+Kcopyd provides the ability to copy a range of sectors from one block-device
+to one or more other block-devices, with an asynchronous completion
+notification. It is used by dm-snapshot and dm-mirror.
+
+Users of kcopyd must first create a client and indicate how many memory pages
+to set aside for their copy jobs. This is done with a call to
+kcopyd_client_create().
+
+   int kcopyd_client_create(unsigned int num_pages,
+                            struct kcopyd_client **result);
+
+To start a copy job, the user must set up io_region structures to describe
+the source and destinations of the copy. Each io_region indicates a
+block-device along with the starting sector and size of the region. The source
+of the copy is given as one io_region structure, and the destinations of the
+copy are given as an array of io_region structures.
+
+   struct io_region {
+      struct block_device *bdev;
+      sector_t sector;
+      sector_t count;
+   };
+
+To start the copy, the user calls kcopyd_copy(), passing in the client
+pointer, pointers to the source and destination io_regions, the name of a
+completion callback routine, and a pointer to some context data for the copy.
+
+   int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from,
+                   unsigned int num_dests, struct io_region *dests,
+                   unsigned int flags, kcopyd_notify_fn fn, void *context);
+
+   typedef void (*kcopyd_notify_fn)(int read_err, unsigned int write_err,
+                                   void *context);
+
+When the copy completes, kcopyd will call the user's completion routine,
+passing back the user's context pointer. It will also indicate if a read or
+write error occurred during the copy.
+
+When a user is done with all their copy jobs, they should call
+kcopyd_client_destroy() to delete the kcopyd client, which will release the
+associated memory pages.
+
+   void kcopyd_client_destroy(struct kcopyd_client *kc);
+
diff --git a/doc/kernel/linear.txt b/doc/kernel/linear.txt
new file mode 100644 (file)
index 0000000..d5307d3
--- /dev/null
@@ -0,0 +1,61 @@
+dm-linear
+=========
+
+Device-Mapper's "linear" target maps a linear range of the Device-Mapper
+device onto a linear range of another device.  This is the basic building
+block of logical volume managers.
+
+Parameters: <dev path> <offset>
+    <dev path>: Full pathname to the underlying block-device, or a
+                "major:minor" device-number.
+    <offset>: Starting sector within the device.
+
+
+Example scripts
+===============
+[[
+#!/bin/sh
+# Create an identity mapping for a device
+echo "0 `blockdev --getsize $1` linear $1 0" | dmsetup create identity
+]]
+
+
+[[
+#!/bin/sh
+# Join 2 devices together
+size1=`blockdev --getsize $1`
+size2=`blockdev --getsize $2`
+echo "0 $size1 linear $1 0
+$size1 $size2 linear $2 0" | dmsetup create joined
+]]
+
+
+[[
+#!/usr/bin/perl -w
+# Split a device into 4M chunks and then join them together in reverse order.
+
+my $name = "reverse";
+my $extent_size = 4 * 1024 * 2;
+my $dev = $ARGV[0];
+my $table = "";
+my $count = 0;
+
+if (!defined($dev)) {
+        die("Please specify a device.\n");
+}
+
+my $dev_size = `blockdev --getsize $dev`;
+my $extents = int($dev_size / $extent_size) -
+              (($dev_size % $extent_size) ? 1 : 0);
+
+while ($extents > 0) {
+        my $this_start = $count * $extent_size;
+        $extents--;
+        $count++;
+        my $this_offset = $extents * $extent_size;
+
+        $table .= "$this_start $extent_size linear $dev $this_offset\n";
+}
+
+`echo \"$table\" | dmsetup create $name`;
+]]
diff --git a/doc/kernel/log.txt b/doc/kernel/log.txt
new file mode 100644 (file)
index 0000000..c155ac5
--- /dev/null
@@ -0,0 +1,54 @@
+Device-Mapper Logging
+=====================
+The device-mapper logging code is used by some of the device-mapper
+RAID targets to track regions of the disk that are not consistent.
+A region (or portion of the address space) of the disk may be
+inconsistent because a RAID stripe is currently being operated on or
+a machine died while the region was being altered.  In the case of
+mirrors, a region would be considered dirty/inconsistent while you
+are writing to it because the writes need to be replicated for all
+the legs of the mirror and may not reach the legs at the same time.
+Once all writes are complete, the region is considered clean again.
+
+There is a generic logging interface that the device-mapper RAID
+implementations use to perform logging operations (see
+dm_dirty_log_type in include/linux/dm-dirty-log.h).  Various different
+logging implementations are available and provide different
+capabilities.  The list includes:
+
+Type           Files
+====           =====
+disk           drivers/md/dm-log.c
+core           drivers/md/dm-log.c
+userspace      drivers/md/dm-log-userspace* include/linux/dm-log-userspace.h
+
+The "disk" log type
+-------------------
+This log implementation commits the log state to disk.  This way, the
+logging state survives reboots/crashes.
+
+The "core" log type
+-------------------
+This log implementation keeps the log state in memory.  The log state
+will not survive a reboot or crash, but there may be a small boost in
+performance.  This method can also be used if no storage device is
+available for storing log state.
+
+The "userspace" log type
+------------------------
+This log type simply provides a way to export the log API to userspace,
+so log implementations can be done there.  This is done by forwarding most
+logging requests to userspace, where a daemon receives and processes the
+request.
+
+The structure used for communication between kernel and userspace are
+located in include/linux/dm-log-userspace.h.  Due to the frequency,
+diversity, and 2-way communication nature of the exchanges between
+kernel and userspace, 'connector' is used as the interface for
+communication.
+
+There are currently two userspace log implementations that leverage this
+framework - "clustered-disk" and "clustered-core".  These implementations
+provide a cluster-coherent log for shared-storage.  Device-mapper mirroring
+can be used in a shared-storage environment when the cluster log implementations
+are employed.
diff --git a/doc/kernel/persistent-data.txt b/doc/kernel/persistent-data.txt
new file mode 100644 (file)
index 0000000..a333bcb
--- /dev/null
@@ -0,0 +1,84 @@
+Introduction
+============
+
+The more-sophisticated device-mapper targets require complex metadata
+that is managed in kernel.  In late 2010 we were seeing that various
+different targets were rolling their own data structures, for example:
+
+- Mikulas Patocka's multisnap implementation
+- Heinz Mauelshagen's thin provisioning target
+- Another btree-based caching target posted to dm-devel
+- Another multi-snapshot target based on a design of Daniel Phillips
+
+Maintaining these data structures takes a lot of work, so if possible
+we'd like to reduce the number.
+
+The persistent-data library is an attempt to provide a re-usable
+framework for people who want to store metadata in device-mapper
+targets.  It's currently used by the thin-provisioning target and an
+upcoming hierarchical storage target.
+
+Overview
+========
+
+The main documentation is in the header files which can all be found
+under drivers/md/persistent-data.
+
+The block manager
+-----------------
+
+dm-block-manager.[hc]
+
+This provides access to the data on disk in fixed sized-blocks.  There
+is a read/write locking interface to prevent concurrent accesses, and
+keep data that is being used in the cache.
+
+Clients of persistent-data are unlikely to use this directly.
+
+The transaction manager
+-----------------------
+
+dm-transaction-manager.[hc]
+
+This restricts access to blocks and enforces copy-on-write semantics.
+The only way you can get hold of a writable block through the
+transaction manager is by shadowing an existing block (ie. doing
+copy-on-write) or allocating a fresh one.  Shadowing is elided within
+the same transaction so performance is reasonable.  The commit method
+ensures that all data is flushed before it writes the superblock.
+On power failure your metadata will be as it was when last committed.
+
+The Space Maps
+--------------
+
+dm-space-map.h
+dm-space-map-metadata.[hc]
+dm-space-map-disk.[hc]
+
+On-disk data structures that keep track of reference counts of blocks.
+Also acts as the allocator of new blocks.  Currently two
+implementations: a simpler one for managing blocks on a different
+device (eg. thinly-provisioned data blocks); and one for managing
+the metadata space.  The latter is complicated by the need to store
+its own data within the space it's managing.
+
+The data structures
+-------------------
+
+dm-btree.[hc]
+dm-btree-remove.c
+dm-btree-spine.c
+dm-btree-internal.h
+
+Currently there is only one data structure, a hierarchical btree.
+There are plans to add more.  For example, something with an
+array-like interface would see a lot of use.
+
+The btree is 'hierarchical' in that you can define it to be composed
+of nested btrees, and take multiple keys.  For example, the
+thin-provisioning target uses a btree with two levels of nesting.
+The first maps a device id to a mapping tree, and that in turn maps a
+virtual block to a physical block.
+
+Values stored in the btrees can have arbitrary size.  Keys are always
+64bits, although nesting allows you to use multiple keys.
diff --git a/doc/kernel/queue-length.txt b/doc/kernel/queue-length.txt
new file mode 100644 (file)
index 0000000..f4db256
--- /dev/null
@@ -0,0 +1,39 @@
+dm-queue-length
+===============
+
+dm-queue-length is a path selector module for device-mapper targets,
+which selects a path with the least number of in-flight I/Os.
+The path selector name is 'queue-length'.
+
+Table parameters for each path: [<repeat_count>]
+       <repeat_count>: The number of I/Os to dispatch using the selected
+                       path before switching to the next path.
+                       If not given, internal default is used. To check
+                       the default value, see the activated table.
+
+Status for each path: <status> <fail-count> <in-flight>
+       <status>: 'A' if the path is active, 'F' if the path is failed.
+       <fail-count>: The number of path failures.
+       <in-flight>: The number of in-flight I/Os on the path.
+
+
+Algorithm
+=========
+
+dm-queue-length increments/decrements 'in-flight' when an I/O is
+dispatched/completed respectively.
+dm-queue-length selects a path with the minimum 'in-flight'.
+
+
+Examples
+========
+In case that 2 paths (sda and sdb) are used with repeat_count == 128.
+
+# echo "0 10 multipath 0 0 1 1 queue-length 0 2 1 8:0 128 8:16 128" \
+  dmsetup create test
+#
+# dmsetup table
+test: 0 10 multipath 0 0 1 1 queue-length 0 2 1 8:0 128 8:16 128
+#
+# dmsetup status
+test: 0 10 multipath 2 0 0 0 1 1 E 0 2 1 8:0 A 0 0 8:16 A 0 0
diff --git a/doc/kernel/raid.txt b/doc/kernel/raid.txt
new file mode 100644 (file)
index 0000000..946c733
--- /dev/null
@@ -0,0 +1,108 @@
+dm-raid
+-------
+
+The device-mapper RAID (dm-raid) target provides a bridge from DM to MD.
+It allows the MD RAID drivers to be accessed using a device-mapper
+interface.
+
+The target is named "raid" and it accepts the following parameters:
+
+  <raid_type> <#raid_params> <raid_params> \
+    <#raid_devs> <metadata_dev0> <dev0> [.. <metadata_devN> <devN>]
+
+<raid_type>:
+  raid1                RAID1 mirroring
+  raid4                RAID4 dedicated parity disk
+  raid5_la     RAID5 left asymmetric
+               - rotating parity 0 with data continuation
+  raid5_ra     RAID5 right asymmetric
+               - rotating parity N with data continuation
+  raid5_ls     RAID5 left symmetric
+               - rotating parity 0 with data restart
+  raid5_rs     RAID5 right symmetric
+               - rotating parity N with data restart
+  raid6_zr     RAID6 zero restart
+               - rotating parity zero (left-to-right) with data restart
+  raid6_nr     RAID6 N restart
+               - rotating parity N (right-to-left) with data restart
+  raid6_nc     RAID6 N continue
+               - rotating parity N (right-to-left) with data continuation
+
+  Reference: Chapter 4 of
+  http://www.snia.org/sites/default/files/SNIA_DDF_Technical_Position_v2.0.pdf
+
+<#raid_params>: The number of parameters that follow.
+
+<raid_params> consists of
+    Mandatory parameters:
+        <chunk_size>: Chunk size in sectors.  This parameter is often known as
+                     "stripe size".  It is the only mandatory parameter and
+                     is placed first.
+
+    followed by optional parameters (in any order):
+       [sync|nosync]   Force or prevent RAID initialization.
+
+       [rebuild <idx>] Rebuild drive number idx (first drive is 0).
+
+       [daemon_sleep <ms>]
+               Interval between runs of the bitmap daemon that
+               clear bits.  A longer interval means less bitmap I/O but
+               resyncing after a failure is likely to take longer.
+
+       [min_recovery_rate <kB/sec/disk>]  Throttle RAID initialization
+       [max_recovery_rate <kB/sec/disk>]  Throttle RAID initialization
+       [write_mostly <idx>]               Drive index is write-mostly
+       [max_write_behind <sectors>]       See '-write-behind=' (man mdadm)
+       [stripe_cache <sectors>]           Stripe cache size (higher RAIDs only)
+       [region_size <sectors>]
+               The region_size multiplied by the number of regions is the
+               logical size of the array.  The bitmap records the device
+               synchronisation state for each region.
+
+<#raid_devs>: The number of devices composing the array.
+       Each device consists of two entries.  The first is the device
+       containing the metadata (if any); the second is the one containing the
+       data.
+
+       If a drive has failed or is missing at creation time, a '-' can be
+       given for both the metadata and data drives for a given position.
+
+
+Example tables
+--------------
+# RAID4 - 4 data drives, 1 parity (no metadata devices)
+# No metadata devices specified to hold superblock/bitmap info
+# Chunk size of 1MiB
+# (Lines separated for easy reading)
+
+0 1960893648 raid \
+        raid4 1 2048 \
+        5 - 8:17 - 8:33 - 8:49 - 8:65 - 8:81
+
+# RAID4 - 4 data drives, 1 parity (with metadata devices)
+# Chunk size of 1MiB, force RAID initialization,
+#       min recovery rate at 20 kiB/sec/disk
+
+0 1960893648 raid \
+        raid4 4 2048 sync min_recovery_rate 20 \
+        5 8:17 8:18 8:33 8:34 8:49 8:50 8:65 8:66 8:81 8:82
+
+'dmsetup table' displays the table used to construct the mapping.
+The optional parameters are always printed in the order listed
+above with "sync" or "nosync" always output ahead of the other
+arguments, regardless of the order used when originally loading the table.
+Arguments that can be repeated are ordered by value.
+
+'dmsetup status' yields information on the state and health of the
+array.
+The output is as follows:
+1: <s> <l> raid \
+2:      <raid_type> <#devices> <1 health char for each dev> <resync_ratio>
+
+Line 1 is the standard output produced by device-mapper.
+Line 2 is produced by the raid target, and best explained by example:
+        0 1960893648 raid raid4 5 AAAAA 2/490221568
+Here we can see the RAID type is raid4, there are 5 devices - all of
+which are 'A'live, and the array is 2/490221568 complete with recovery.
+Faulty or missing devices are marked 'D'.  Devices that are out-of-sync
+are marked 'a'.
diff --git a/doc/kernel/service-time.txt b/doc/kernel/service-time.txt
new file mode 100644 (file)
index 0000000..fb1d4a0
--- /dev/null
@@ -0,0 +1,91 @@
+dm-service-time
+===============
+
+dm-service-time is a path selector module for device-mapper targets,
+which selects a path with the shortest estimated service time for
+the incoming I/O.
+
+The service time for each path is estimated by dividing the total size
+of in-flight I/Os on a path with the performance value of the path.
+The performance value is a relative throughput value among all paths
+in a path-group, and it can be specified as a table argument.
+
+The path selector name is 'service-time'.
+
+Table parameters for each path: [<repeat_count> [<relative_throughput>]]
+       <repeat_count>: The number of I/Os to dispatch using the selected
+                       path before switching to the next path.
+                       If not given, internal default is used.  To check
+                       the default value, see the activated table.
+       <relative_throughput>: The relative throughput value of the path
+                       among all paths in the path-group.
+                       The valid range is 0-100.
+                       If not given, minimum value '1' is used.
+                       If '0' is given, the path isn't selected while
+                       other paths having a positive value are available.
+
+Status for each path: <status> <fail-count> <in-flight-size> \
+                     <relative_throughput>
+       <status>: 'A' if the path is active, 'F' if the path is failed.
+       <fail-count>: The number of path failures.
+       <in-flight-size>: The size of in-flight I/Os on the path.
+       <relative_throughput>: The relative throughput value of the path
+                       among all paths in the path-group.
+
+
+Algorithm
+=========
+
+dm-service-time adds the I/O size to 'in-flight-size' when the I/O is
+dispatched and subtracts when completed.
+Basically, dm-service-time selects a path having minimum service time
+which is calculated by:
+
+       ('in-flight-size' + 'size-of-incoming-io') / 'relative_throughput'
+
+However, some optimizations below are used to reduce the calculation
+as much as possible.
+
+       1. If the paths have the same 'relative_throughput', skip
+          the division and just compare the 'in-flight-size'.
+
+       2. If the paths have the same 'in-flight-size', skip the division
+          and just compare the 'relative_throughput'.
+
+       3. If some paths have non-zero 'relative_throughput' and others
+          have zero 'relative_throughput', ignore those paths with zero
+          'relative_throughput'.
+
+If such optimizations can't be applied, calculate service time, and
+compare service time.
+If calculated service time is equal, the path having maximum
+'relative_throughput' may be better.  So compare 'relative_throughput'
+then.
+
+
+Examples
+========
+In case that 2 paths (sda and sdb) are used with repeat_count == 128
+and sda has an average throughput 1GB/s and sdb has 4GB/s,
+'relative_throughput' value may be '1' for sda and '4' for sdb.
+
+# echo "0 10 multipath 0 0 1 1 service-time 0 2 2 8:0 128 1 8:16 128 4" \
+  dmsetup create test
+#
+# dmsetup table
+test: 0 10 multipath 0 0 1 1 service-time 0 2 2 8:0 128 1 8:16 128 4
+#
+# dmsetup status
+test: 0 10 multipath 2 0 0 0 1 1 E 0 2 2 8:0 A 0 0 1 8:16 A 0 0 4
+
+
+Or '2' for sda and '8' for sdb would be also true.
+
+# echo "0 10 multipath 0 0 1 1 service-time 0 2 2 8:0 128 2 8:16 128 8" \
+  dmsetup create test
+#
+# dmsetup table
+test: 0 10 multipath 0 0 1 1 service-time 0 2 2 8:0 128 2 8:16 128 8
+#
+# dmsetup status
+test: 0 10 multipath 2 0 0 0 1 1 E 0 2 2 8:0 A 0 0 2 8:16 A 0 0 8
diff --git a/doc/kernel/snapshot.txt b/doc/kernel/snapshot.txt
new file mode 100644 (file)
index 0000000..0d5bc46
--- /dev/null
@@ -0,0 +1,168 @@
+Device-mapper snapshot support
+==============================
+
+Device-mapper allows you, without massive data copying:
+
+*) To create snapshots of any block device i.e. mountable, saved states of
+the block device which are also writable without interfering with the
+original content;
+*) To create device "forks", i.e. multiple different versions of the
+same data stream.
+*) To merge a snapshot of a block device back into the snapshot's origin
+device.
+
+In the first two cases, dm copies only the chunks of data that get
+changed and uses a separate copy-on-write (COW) block device for
+storage.
+
+For snapshot merge the contents of the COW storage are merged back into
+the origin device.
+
+
+There are three dm targets available:
+snapshot, snapshot-origin, and snapshot-merge.
+
+*) snapshot-origin <origin>
+
+which will normally have one or more snapshots based on it.
+Reads will be mapped directly to the backing device. For each write, the
+original data will be saved in the <COW device> of each snapshot to keep
+its visible content unchanged, at least until the <COW device> fills up.
+
+
+*) snapshot <origin> <COW device> <persistent?> <chunksize>
+
+A snapshot of the <origin> block device is created. Changed chunks of
+<chunksize> sectors will be stored on the <COW device>.  Writes will
+only go to the <COW device>.  Reads will come from the <COW device> or
+from <origin> for unchanged data.  <COW device> will often be
+smaller than the origin and if it fills up the snapshot will become
+useless and be disabled, returning errors.  So it is important to monitor
+the amount of free space and expand the <COW device> before it fills up.
+
+<persistent?> is P (Persistent) or N (Not persistent - will not survive
+after reboot).
+The difference is that for transient snapshots less metadata must be
+saved on disk - they can be kept in memory by the kernel.
+
+
+* snapshot-merge <origin> <COW device> <persistent> <chunksize>
+
+takes the same table arguments as the snapshot target except it only
+works with persistent snapshots.  This target assumes the role of the
+"snapshot-origin" target and must not be loaded if the "snapshot-origin"
+is still present for <origin>.
+
+Creates a merging snapshot that takes control of the changed chunks
+stored in the <COW device> of an existing snapshot, through a handover
+procedure, and merges these chunks back into the <origin>.  Once merging
+has started (in the background) the <origin> may be opened and the merge
+will continue while I/O is flowing to it.  Changes to the <origin> are
+deferred until the merging snapshot's corresponding chunk(s) have been
+merged.  Once merging has started the snapshot device, associated with
+the "snapshot" target, will return -EIO when accessed.
+
+
+How snapshot is used by LVM2
+============================
+When you create the first LVM2 snapshot of a volume, four dm devices are used:
+
+1) a device containing the original mapping table of the source volume;
+2) a device used as the <COW device>;
+3) a "snapshot" device, combining #1 and #2, which is the visible snapshot
+   volume;
+4) the "original" volume (which uses the device number used by the original
+   source volume), whose table is replaced by a "snapshot-origin" mapping
+   from device #1.
+
+A fixed naming scheme is used, so with the following commands:
+
+lvcreate -L 1G -n base volumeGroup
+lvcreate -L 100M --snapshot -n snap volumeGroup/base
+
+we'll have this situation (with volumes in above order):
+
+# dmsetup table|grep volumeGroup
+
+volumeGroup-base-real: 0 2097152 linear 8:19 384
+volumeGroup-snap-cow: 0 204800 linear 8:19 2097536
+volumeGroup-snap: 0 2097152 snapshot 254:11 254:12 P 16
+volumeGroup-base: 0 2097152 snapshot-origin 254:11
+
+# ls -lL /dev/mapper/volumeGroup-*
+brw-------  1 root root 254, 11 29 ago 18:15 /dev/mapper/volumeGroup-base-real
+brw-------  1 root root 254, 12 29 ago 18:15 /dev/mapper/volumeGroup-snap-cow
+brw-------  1 root root 254, 13 29 ago 18:15 /dev/mapper/volumeGroup-snap
+brw-------  1 root root 254, 10 29 ago 18:14 /dev/mapper/volumeGroup-base
+
+
+How snapshot-merge is used by LVM2
+==================================
+A merging snapshot assumes the role of the "snapshot-origin" while
+merging.  As such the "snapshot-origin" is replaced with
+"snapshot-merge".  The "-real" device is not changed and the "-cow"
+device is renamed to <origin name>-cow to aid LVM2's cleanup of the
+merging snapshot after it completes.  The "snapshot" that hands over its
+COW device to the "snapshot-merge" is deactivated (unless using lvchange
+--refresh); but if it is left active it will simply return I/O errors.
+
+A snapshot will merge into its origin with the following command:
+
+lvconvert --merge volumeGroup/snap
+
+we'll now have this situation:
+
+# dmsetup table|grep volumeGroup
+
+volumeGroup-base-real: 0 2097152 linear 8:19 384
+volumeGroup-base-cow: 0 204800 linear 8:19 2097536
+volumeGroup-base: 0 2097152 snapshot-merge 254:11 254:12 P 16
+
+# ls -lL /dev/mapper/volumeGroup-*
+brw-------  1 root root 254, 11 29 ago 18:15 /dev/mapper/volumeGroup-base-real
+brw-------  1 root root 254, 12 29 ago 18:16 /dev/mapper/volumeGroup-base-cow
+brw-------  1 root root 254, 10 29 ago 18:16 /dev/mapper/volumeGroup-base
+
+
+How to determine when a merging is complete
+===========================================
+The snapshot-merge and snapshot status lines end with:
+  <sectors_allocated>/<total_sectors> <metadata_sectors>
+
+Both <sectors_allocated> and <total_sectors> include both data and metadata.
+During merging, the number of sectors allocated gets smaller and
+smaller.  Merging has finished when the number of sectors holding data
+is zero, in other words <sectors_allocated> == <metadata_sectors>.
+
+Here is a practical example (using a hybrid of lvm and dmsetup commands):
+
+# lvs
+  LV      VG          Attr   LSize Origin  Snap%  Move Log Copy%  Convert
+  base    volumeGroup owi-a- 4.00g
+  snap    volumeGroup swi-a- 1.00g base  18.97
+
+# dmsetup status volumeGroup-snap
+0 8388608 snapshot 397896/2097152 1560
+                                  ^^^^ metadata sectors
+
+# lvconvert --merge -b volumeGroup/snap
+  Merging of volume snap started.
+
+# lvs volumeGroup/snap
+  LV      VG          Attr   LSize Origin  Snap%  Move Log Copy%  Convert
+  base    volumeGroup Owi-a- 4.00g          17.23
+
+# dmsetup status volumeGroup-base
+0 8388608 snapshot-merge 281688/2097152 1104
+
+# dmsetup status volumeGroup-base
+0 8388608 snapshot-merge 180480/2097152 712
+
+# dmsetup status volumeGroup-base
+0 8388608 snapshot-merge 16/2097152 16
+
+Merging has finished.
+
+# lvs
+  LV      VG          Attr   LSize Origin  Snap%  Move Log Copy%  Convert
+  base    volumeGroup owi-a- 4.00g
diff --git a/doc/kernel/striped.txt b/doc/kernel/striped.txt
new file mode 100644 (file)
index 0000000..45f3b91
--- /dev/null
@@ -0,0 +1,57 @@
+dm-stripe
+=========
+
+Device-Mapper's "striped" target is used to create a striped (i.e. RAID-0)
+device across one or more underlying devices. Data is written in "chunks",
+with consecutive chunks rotating among the underlying devices. This can
+potentially provide improved I/O throughput by utilizing several physical
+devices in parallel.
+
+Parameters: <num devs> <chunk size> [<dev path> <offset>]+
+    <num devs>: Number of underlying devices.
+    <chunk size>: Size of each chunk of data. Must be at least as
+                  large as the system's PAGE_SIZE.
+    <dev path>: Full pathname to the underlying block-device, or a
+                "major:minor" device-number.
+    <offset>: Starting sector within the device.
+
+One or more underlying devices can be specified. The striped device size must
+be a multiple of the chunk size multiplied by the number of underlying devices.
+
+
+Example scripts
+===============
+
+[[
+#!/usr/bin/perl -w
+# Create a striped device across any number of underlying devices. The device
+# will be called "stripe_dev" and have a chunk-size of 128k.
+
+my $chunk_size = 128 * 2;
+my $dev_name = "stripe_dev";
+my $num_devs = @ARGV;
+my @devs = @ARGV;
+my ($min_dev_size, $stripe_dev_size, $i);
+
+if (!$num_devs) {
+        die("Specify at least one device\n");
+}
+
+$min_dev_size = `blockdev --getsize $devs[0]`;
+for ($i = 1; $i < $num_devs; $i++) {
+        my $this_size = `blockdev --getsize $devs[$i]`;
+        $min_dev_size = ($min_dev_size < $this_size) ?
+                        $min_dev_size : $this_size;
+}
+
+$stripe_dev_size = $min_dev_size * $num_devs;
+$stripe_dev_size -= $stripe_dev_size % ($chunk_size * $num_devs);
+
+$table = "0 $stripe_dev_size striped $num_devs $chunk_size";
+for ($i = 0; $i < $num_devs; $i++) {
+        $table .= " $devs[$i] 0";
+}
+
+`echo $table | dmsetup create $dev_name`;
+]]
+
diff --git a/doc/kernel/thin-provisioning.txt b/doc/kernel/thin-provisioning.txt
new file mode 100644 (file)
index 0000000..f5cfc62
--- /dev/null
@@ -0,0 +1,331 @@
+Introduction
+============
+
+This document describes a collection of device-mapper targets that
+between them implement thin-provisioning and snapshots.
+
+The main highlight of this implementation, compared to the previous
+implementation of snapshots, is that it allows many virtual devices to
+be stored on the same data volume.  This simplifies administration and
+allows the sharing of data between volumes, thus reducing disk usage.
+
+Another significant feature is support for an arbitrary depth of
+recursive snapshots (snapshots of snapshots of snapshots ...).  The
+previous implementation of snapshots did this by chaining together
+lookup tables, and so performance was O(depth).  This new
+implementation uses a single data structure to avoid this degradation
+with depth.  Fragmentation may still be an issue, however, in some
+scenarios.
+
+Metadata is stored on a separate device from data, giving the
+administrator some freedom, for example to:
+
+- Improve metadata resilience by storing metadata on a mirrored volume
+  but data on a non-mirrored one.
+
+- Improve performance by storing the metadata on SSD.
+
+Status
+======
+
+These targets are very much still in the EXPERIMENTAL state.  Please
+do not yet rely on them in production.  But do experiment and offer us
+feedback.  Different use cases will have different performance
+characteristics, for example due to fragmentation of the data volume.
+
+If you find this software is not performing as expected please mail
+dm-devel@redhat.com with details and we'll try our best to improve
+things for you.
+
+Userspace tools for checking and repairing the metadata are under
+development.
+
+Cookbook
+========
+
+This section describes some quick recipes for using thin provisioning.
+They use the dmsetup program to control the device-mapper driver
+directly.  End users will be advised to use a higher-level volume
+manager such as LVM2 once support has been added.
+
+Pool device
+-----------
+
+The pool device ties together the metadata volume and the data volume.
+It maps I/O linearly to the data volume and updates the metadata via
+two mechanisms:
+
+- Function calls from the thin targets
+
+- Device-mapper 'messages' from userspace which control the creation of new
+  virtual devices amongst other things.
+
+Setting up a fresh pool device
+------------------------------
+
+Setting up a pool device requires a valid metadata device, and a
+data device.  If you do not have an existing metadata device you can
+make one by zeroing the first 4k to indicate empty metadata.
+
+    dd if=/dev/zero of=$metadata_dev bs=4096 count=1
+
+The amount of metadata you need will vary according to how many blocks
+are shared between thin devices (i.e. through snapshots).  If you have
+less sharing than average you'll need a larger-than-average metadata device.
+
+As a guide, we suggest you calculate the number of bytes to use in the
+metadata device as 48 * $data_dev_size / $data_block_size but round it up
+to 2MB if the answer is smaller.  If you're creating large numbers of
+snapshots which are recording large amounts of change, you may find you
+need to increase this.
+
+The largest size supported is 16GB: If the device is larger,
+a warning will be issued and the excess space will not be used.
+
+Reloading a pool table
+----------------------
+
+You may reload a pool's table, indeed this is how the pool is resized
+if it runs out of space.  (N.B. While specifying a different metadata
+device when reloading is not forbidden at the moment, things will go
+wrong if it does not route I/O to exactly the same on-disk location as
+previously.)
+
+Using an existing pool device
+-----------------------------
+
+    dmsetup create pool \
+       --table "0 20971520 thin-pool $metadata_dev $data_dev \
+                $data_block_size $low_water_mark"
+
+$data_block_size gives the smallest unit of disk space that can be
+allocated at a time expressed in units of 512-byte sectors.  People
+primarily interested in thin provisioning may want to use a value such
+as 1024 (512KB).  People doing lots of snapshotting may want a smaller value
+such as 128 (64KB).  If you are not zeroing newly-allocated data,
+a larger $data_block_size in the region of 256000 (128MB) is suggested.
+$data_block_size must be the same for the lifetime of the
+metadata device.
+
+$low_water_mark is expressed in blocks of size $data_block_size.  If
+free space on the data device drops below this level then a dm event
+will be triggered which a userspace daemon should catch allowing it to
+extend the pool device.  Only one such event will be sent.
+Resuming a device with a new table itself triggers an event so the
+userspace daemon can use this to detect a situation where a new table
+already exceeds the threshold.
+
+Thin provisioning
+-----------------
+
+i) Creating a new thinly-provisioned volume.
+
+  To create a new thinly- provisioned volume you must send a message to an
+  active pool device, /dev/mapper/pool in this example.
+
+    dmsetup message /dev/mapper/pool 0 "create_thin 0"
+
+  Here '0' is an identifier for the volume, a 24-bit number.  It's up
+  to the caller to allocate and manage these identifiers.  If the
+  identifier is already in use, the message will fail with -EEXIST.
+
+ii) Using a thinly-provisioned volume.
+
+  Thinly-provisioned volumes are activated using the 'thin' target:
+
+    dmsetup create thin --table "0 2097152 thin /dev/mapper/pool 0"
+
+  The last parameter is the identifier for the thinp device.
+
+Internal snapshots
+------------------
+
+i) Creating an internal snapshot.
+
+  Snapshots are created with another message to the pool.
+
+  N.B.  If the origin device that you wish to snapshot is active, you
+  must suspend it before creating the snapshot to avoid corruption.
+  This is NOT enforced at the moment, so please be careful!
+
+    dmsetup suspend /dev/mapper/thin
+    dmsetup message /dev/mapper/pool 0 "create_snap 1 0"
+    dmsetup resume /dev/mapper/thin
+
+  Here '1' is the identifier for the volume, a 24-bit number.  '0' is the
+  identifier for the origin device.
+
+ii) Using an internal snapshot.
+
+  Once created, the user doesn't have to worry about any connection
+  between the origin and the snapshot.  Indeed the snapshot is no
+  different from any other thinly-provisioned device and can be
+  snapshotted itself via the same method.  It's perfectly legal to
+  have only one of them active, and there's no ordering requirement on
+  activating or removing them both.  (This differs from conventional
+  device-mapper snapshots.)
+
+  Activate it exactly the same way as any other thinly-provisioned volume:
+
+    dmsetup create snap --table "0 2097152 thin /dev/mapper/pool 1"
+
+External snapshots
+------------------
+
+You can use an external _read only_ device as an origin for a
+thinly-provisioned volume.  Any read to an unprovisioned area of the
+thin device will be passed through to the origin.  Writes trigger
+the allocation of new blocks as usual.
+
+One use case for this is VM hosts that want to run guests on
+thinly-provisioned volumes but have the base image on another device
+(possibly shared between many VMs).
+
+You must not write to the origin device if you use this technique!
+Of course, you may write to the thin device and take internal snapshots
+of the thin volume.
+
+i) Creating a snapshot of an external device
+
+  This is the same as creating a thin device.
+  You don't mention the origin at this stage.
+
+    dmsetup message /dev/mapper/pool 0 "create_thin 0"
+
+ii) Using a snapshot of an external device.
+
+  Append an extra parameter to the thin target specifying the origin:
+
+    dmsetup create snap --table "0 2097152 thin /dev/mapper/pool 0 /dev/image"
+
+  N.B. All descendants (internal snapshots) of this snapshot require the
+  same extra origin parameter.
+
+Deactivation
+------------
+
+All devices using a pool must be deactivated before the pool itself
+can be.
+
+    dmsetup remove thin
+    dmsetup remove snap
+    dmsetup remove pool
+
+Reference
+=========
+
+'thin-pool' target
+------------------
+
+i) Constructor
+
+    thin-pool <metadata dev> <data dev> <data block size (sectors)> \
+             <low water mark (blocks)> [<number of feature args> [<arg>]*]
+
+    Optional feature arguments:
+
+      skip_block_zeroing: Skip the zeroing of newly-provisioned blocks.
+
+      ignore_discard: Disable discard support.
+
+      no_discard_passdown: Don't pass discards down to the underlying
+                          data device, but just remove the mapping.
+
+    Data block size must be between 64KB (128 sectors) and 1GB
+    (2097152 sectors) inclusive.
+
+
+ii) Status
+
+    <transaction id> <used metadata blocks>/<total metadata blocks>
+    <used data blocks>/<total data blocks> <held metadata root>
+
+
+    transaction id:
+       A 64-bit number used by userspace to help synchronise with metadata
+       from volume managers.
+
+    used data blocks / total data blocks
+       If the number of free blocks drops below the pool's low water mark a
+       dm event will be sent to userspace.  This event is edge-triggered and
+       it will occur only once after each resume so volume manager writers
+       should register for the event and then check the target's status.
+
+    held metadata root:
+       The location, in sectors, of the metadata root that has been
+       'held' for userspace read access.  '-' indicates there is no
+       held root.  This feature is not yet implemented so '-' is
+       always returned.
+
+iii) Messages
+
+    create_thin <dev id>
+
+       Create a new thinly-provisioned device.
+       <dev id> is an arbitrary unique 24-bit identifier chosen by
+       the caller.
+
+    create_snap <dev id> <origin id>
+
+       Create a new snapshot of another thinly-provisioned device.
+       <dev id> is an arbitrary unique 24-bit identifier chosen by
+       the caller.
+       <origin id> is the identifier of the thinly-provisioned device
+       of which the new device will be a snapshot.
+
+    delete <dev id>
+
+       Deletes a thin device.  Irreversible.
+
+    set_transaction_id <current id> <new id>
+
+       Userland volume managers, such as LVM, need a way to
+       synchronise their external metadata with the internal metadata of the
+       pool target.  The thin-pool target offers to store an
+       arbitrary 64-bit transaction id and return it on the target's
+       status line.  To avoid races you must provide what you think
+       the current transaction id is when you change it with this
+       compare-and-swap message.
+
+    reserve_metadata_snap
+
+        Reserve a copy of the data mapping btree for use by userland.
+        This allows userland to inspect the mappings as they were when
+        this message was executed.  Use the pool's status command to
+        get the root block associated with the metadata snapshot.
+
+    release_metadata_snap
+
+        Release a previously reserved copy of the data mapping btree.
+
+'thin' target
+-------------
+
+i) Constructor
+
+    thin <pool dev> <dev id> [<external origin dev>]
+
+    pool dev:
+       the thin-pool device, e.g. /dev/mapper/my_pool or 253:0
+
+    dev id:
+       the internal device identifier of the device to be
+       activated.
+
+    external origin dev:
+       an optional block device outside the pool to be treated as a
+       read-only snapshot origin: reads to unprovisioned areas of the
+       thin target will be mapped to this device.
+
+The pool doesn't store any size against the thin devices.  If you
+load a thin target that is smaller than you've been using previously,
+then you'll have no access to blocks mapped beyond the end.  If you
+load a target that is bigger than before, then extra blocks will be
+provisioned as and when needed.
+
+If you wish to reduce the size of your thin device and potentially
+regain some space then send the 'trim' message to the pool.
+
+ii) Status
+
+     <nr mapped sectors> <highest mapped sector>
diff --git a/doc/kernel/uevent.txt b/doc/kernel/uevent.txt
new file mode 100644 (file)
index 0000000..07edbd8
--- /dev/null
@@ -0,0 +1,97 @@
+The device-mapper uevent code adds the capability to device-mapper to create
+and send kobject uevents (uevents).  Previously device-mapper events were only
+available through the ioctl interface.  The advantage of the uevents interface
+is the event contains environment attributes providing increased context for
+the event avoiding the need to query the state of the device-mapper device after
+the event is received.
+
+There are two functions currently for device-mapper events.  The first function
+listed creates the event and the second function sends the event(s).
+
+void dm_path_uevent(enum dm_uevent_type event_type, struct dm_target *ti,
+                    const char *path, unsigned nr_valid_paths)
+
+void dm_send_uevents(struct list_head *events, struct kobject *kobj)
+
+
+The variables added to the uevent environment are:
+
+Variable Name: DM_TARGET
+Uevent Action(s): KOBJ_CHANGE
+Type: string
+Description:
+Value: Name of device-mapper target that generated the event.
+
+Variable Name: DM_ACTION
+Uevent Action(s): KOBJ_CHANGE
+Type: string
+Description:
+Value: Device-mapper specific action that caused the uevent action.
+       PATH_FAILED - A path has failed.
+       PATH_REINSTATED - A path has been reinstated.
+
+Variable Name: DM_SEQNUM
+Uevent Action(s): KOBJ_CHANGE
+Type: unsigned integer
+Description: A sequence number for this specific device-mapper device.
+Value: Valid unsigned integer range.
+
+Variable Name: DM_PATH
+Uevent Action(s): KOBJ_CHANGE
+Type: string
+Description: Major and minor number of the path device pertaining to this
+event.
+Value: Path name in the form of "Major:Minor"
+
+Variable Name: DM_NR_VALID_PATHS
+Uevent Action(s): KOBJ_CHANGE
+Type: unsigned integer
+Description:
+Value: Valid unsigned integer range.
+
+Variable Name: DM_NAME
+Uevent Action(s): KOBJ_CHANGE
+Type: string
+Description: Name of the device-mapper device.
+Value: Name
+
+Variable Name: DM_UUID
+Uevent Action(s): KOBJ_CHANGE
+Type: string
+Description: UUID of the device-mapper device.
+Value: UUID. (Empty string if there isn't one.)
+
+An example of the uevents generated as captured by udevmonitor is shown
+below.
+
+1.) Path failure.
+UEVENT[1192521009.711215] change@/block/dm-3
+ACTION=change
+DEVPATH=/block/dm-3
+SUBSYSTEM=block
+DM_TARGET=multipath
+DM_ACTION=PATH_FAILED
+DM_SEQNUM=1
+DM_PATH=8:32
+DM_NR_VALID_PATHS=0
+DM_NAME=mpath2
+DM_UUID=mpath-35333333000002328
+MINOR=3
+MAJOR=253
+SEQNUM=1130
+
+2.) Path reinstate.
+UEVENT[1192521132.989927] change@/block/dm-3
+ACTION=change
+DEVPATH=/block/dm-3
+SUBSYSTEM=block
+DM_TARGET=multipath
+DM_ACTION=PATH_REINSTATED
+DM_SEQNUM=2
+DM_PATH=8:32
+DM_NR_VALID_PATHS=1
+DM_NAME=mpath2
+DM_UUID=mpath-35333333000002328
+MINOR=3
+MAJOR=253
+SEQNUM=1131
diff --git a/doc/kernel/verity.txt b/doc/kernel/verity.txt
new file mode 100644 (file)
index 0000000..9884681
--- /dev/null
@@ -0,0 +1,155 @@
+dm-verity
+==========
+
+Device-Mapper's "verity" target provides transparent integrity checking of
+block devices using a cryptographic digest provided by the kernel crypto API.
+This target is read-only.
+
+Construction Parameters
+=======================
+    <version> <dev> <hash_dev>
+    <data_block_size> <hash_block_size>
+    <num_data_blocks> <hash_start_block>
+    <algorithm> <digest> <salt>
+
+<version>
+    This is the type of the on-disk hash format.
+
+    0 is the original format used in the Chromium OS.
+      The salt is appended when hashing, digests are stored continuously and
+      the rest of the block is padded with zeros.
+
+    1 is the current format that should be used for new devices.
+      The salt is prepended when hashing and each digest is
+      padded with zeros to the power of two.
+
+<dev>
+    This is the device containing data, the integrity of which needs to be
+    checked.  It may be specified as a path, like /dev/sdaX, or a device number,
+    <major>:<minor>.
+
+<hash_dev>
+    This is the device that supplies the hash tree data.  It may be
+    specified similarly to the device path and may be the same device.  If the
+    same device is used, the hash_start should be outside the configured
+    dm-verity device.
+
+<data_block_size>
+    The block size on a data device in bytes.
+    Each block corresponds to one digest on the hash device.
+
+<hash_block_size>
+    The size of a hash block in bytes.
+
+<num_data_blocks>
+    The number of data blocks on the data device.  Additional blocks are
+    inaccessible.  You can place hashes to the same partition as data, in this
+    case hashes are placed after <num_data_blocks>.
+
+<hash_start_block>
+    This is the offset, in <hash_block_size>-blocks, from the start of hash_dev
+    to the root block of the hash tree.
+
+<algorithm>
+    The cryptographic hash algorithm used for this device.  This should
+    be the name of the algorithm, like "sha1".
+
+<digest>
+    The hexadecimal encoding of the cryptographic hash of the root hash block
+    and the salt.  This hash should be trusted as there is no other authenticity
+    beyond this point.
+
+<salt>
+    The hexadecimal encoding of the salt value.
+
+Theory of operation
+===================
+
+dm-verity is meant to be set up as part of a verified boot path.  This
+may be anything ranging from a boot using tboot or trustedgrub to just
+booting from a known-good device (like a USB drive or CD).
+
+When a dm-verity device is configured, it is expected that the caller
+has been authenticated in some way (cryptographic signatures, etc).
+After instantiation, all hashes will be verified on-demand during
+disk access.  If they cannot be verified up to the root node of the
+tree, the root hash, then the I/O will fail.  This should detect
+tampering with any data on the device and the hash data.
+
+Cryptographic hashes are used to assert the integrity of the device on a
+per-block basis. This allows for a lightweight hash computation on first read
+into the page cache. Block hashes are stored linearly, aligned to the nearest
+block size.
+
+Hash Tree
+---------
+
+Each node in the tree is a cryptographic hash.  If it is a leaf node, the hash
+of some data block on disk is calculated. If it is an intermediary node,
+the hash of a number of child nodes is calculated.
+
+Each entry in the tree is a collection of neighboring nodes that fit in one
+block.  The number is determined based on block_size and the size of the
+selected cryptographic digest algorithm.  The hashes are linearly-ordered in
+this entry and any unaligned trailing space is ignored but included when
+calculating the parent node.
+
+The tree looks something like:
+
+alg = sha256, num_blocks = 32768, block_size = 4096
+
+                                 [   root    ]
+                                /    . . .    \
+                     [entry_0]                 [entry_1]
+                    /  . . .  \                 . . .   \
+         [entry_0_0]   . . .  [entry_0_127]    . . . .  [entry_1_127]
+           / ... \             /   . . .  \             /           \
+     blk_0 ... blk_127  blk_16256   blk_16383      blk_32640 . . . blk_32767
+
+
+On-disk format
+==============
+
+The verity kernel code does not read the verity metadata on-disk header.
+It only reads the hash blocks which directly follow the header.
+It is expected that a user-space tool will verify the integrity of the
+verity header.
+
+Alternatively, the header can be omitted and the dmsetup parameters can
+be passed via the kernel command-line in a rooted chain of trust where
+the command-line is verified.
+
+Directly following the header (and with sector number padded to the next hash
+block boundary) are the hash blocks which are stored a depth at a time
+(starting from the root), sorted in order of increasing index.
+
+The full specification of kernel parameters and on-disk metadata format
+is available at the cryptsetup project's wiki page
+  http://code.google.com/p/cryptsetup/wiki/DMVerity
+
+Status
+======
+V (for Valid) is returned if every check performed so far was valid.
+If any check failed, C (for Corruption) is returned.
+
+Example
+=======
+Set up a device:
+  # dmsetup create vroot --readonly --table \
+    "0 2097152 verity 1 /dev/sda1 /dev/sda2 4096 4096 262144 1 sha256 "\
+    "4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076 "\
+    "1234000000000000000000000000000000000000000000000000000000000000"
+
+A command line tool veritysetup is available to compute or verify
+the hash tree or activate the kernel device. This is available from
+the cryptsetup upstream repository http://code.google.com/p/cryptsetup/
+(as a libcryptsetup extension).
+
+Create hash on the device:
+  # veritysetup format /dev/sda1 /dev/sda2
+  ...
+  Root hash: 4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076
+
+Activate the device:
+  # veritysetup create vroot /dev/sda1 /dev/sda2 \
+    4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076
diff --git a/doc/kernel/zero.txt b/doc/kernel/zero.txt
new file mode 100644 (file)
index 0000000..20fb38e
--- /dev/null
@@ -0,0 +1,37 @@
+dm-zero
+=======
+
+Device-Mapper's "zero" target provides a block-device that always returns
+zero'd data on reads and silently drops writes. This is similar behavior to
+/dev/zero, but as a block-device instead of a character-device.
+
+Dm-zero has no target-specific parameters.
+
+One very interesting use of dm-zero is for creating "sparse" devices in
+conjunction with dm-snapshot. A sparse device reports a device-size larger
+than the amount of actual storage space available for that device. A user can
+write data anywhere within the sparse device and read it back like a normal
+device. Reads to previously unwritten areas will return a zero'd buffer. When
+enough data has been written to fill up the actual storage space, the sparse
+device is deactivated. This can be very useful for testing device and
+filesystem limitations.
+
+To create a sparse device, start by creating a dm-zero device that's the
+desired size of the sparse device. For this example, we'll assume a 10TB
+sparse device.
+
+TEN_TERABYTES=`expr 10 \* 1024 \* 1024 \* 1024 \* 2`   # 10 TB in sectors
+echo "0 $TEN_TERABYTES zero" | dmsetup create zero1
+
+Then create a snapshot of the zero device, using any available block-device as
+the COW device. The size of the COW device will determine the amount of real
+space available to the sparse device. For this example, we'll assume /dev/sdb1
+is an available 10GB partition.
+
+echo "0 $TEN_TERABYTES snapshot /dev/mapper/zero1 /dev/sdb1 p 128" | \
+   dmsetup create sparse1
+
+This will create a 10TB sparse device called /dev/mapper/sparse1 that has
+10GB of actual storage space available. If more than 10GB of data is written
+to this device, it will start returning I/O errors.
+
diff --git a/doc/lvm2-raid.txt b/doc/lvm2-raid.txt
new file mode 100644 (file)
index 0000000..a6f0915
--- /dev/null
@@ -0,0 +1,475 @@
+=======================
+= LVM RAID Design Doc =
+=======================
+
+#############################
+# Chapter 1: User-Interface #
+#############################
+
+***************** CREATING A RAID DEVICE ******************
+
+01: lvcreate --type <RAID type> \
+02:         [--regionsize <size>] \
+03:         [-i/--stripes <#>] [-I,--stripesize <size>] \
+04:         [-m/--mirrors <#>] \
+05:         [--[min|max]recoveryrate <kB/sec/disk>] \
+06:         [--stripecache <size>] \
+07:         [--writemostly <devices>] \
+08:         [--maxwritebehind <size>] \
+09:         [[no]sync] \
+10:         <Other normal args, like: -L 5G -n lv vg> \
+11:         [devices]
+
+Line 01:
+I don't intend for there to be shorthand options for specifying the
+segment type.  The available RAID types are:
+       "raid0"  - Stripe [NOT IMPLEMENTED]
+       "raid1"  - should replace DM Mirroring
+       "raid10" - striped mirrors, [NOT IMPLEMENTED]
+       "raid4"  - RAID4
+       "raid5"  - Same as "raid5_ls" (Same default as MD)
+       "raid5_la" - RAID5 Rotating parity 0 with data continuation
+       "raid5_ra" - RAID5 Rotating parity N with data continuation
+       "raid5_ls" - RAID5 Rotating parity 0 with data restart
+       "raid5_rs" - RAID5 Rotating parity N with data restart
+       "raid6"    - Same as "raid6_zr"
+       "raid6_zr" - RAID6 Rotating parity 0 with data restart
+       "raid6_nr" - RAID6 Rotating parity N with data restart
+       "raid6_nc" - RAID6 Rotating parity N with data continuation
+The exception to 'no shorthand options' will be where the RAID implementations
+can displace traditional tagets.  This is the case with 'mirror' and 'raid1'.
+In this case, "mirror_segtype_default" - found under the "global" section in
+lvm.conf - can be set to "mirror" or "raid1".  The segment type inferred when
+the '-m' option is used will be taken from this setting.  The default segment
+types can be overridden on the command line by using the '--type' argument.
+
+Line 02:
+Region size is relevant for all RAID types.  It defines the granularity for
+which the bitmap will track the active areas of disk.  The default is currently
+4MiB.  I see no reason to change this unless it is a problem for MD performance.
+MD does impose a restriction of 2^21 regions for a given device, however.  This
+means two things: 1) we should never need a metadata area larger than
+8kiB+sizeof(superblock)+bitmap_offset (IOW, pretty small) and 2) the region
+size will have to be upwardly revised if the device is larger than 8TiB
+(assuming defaults).
+
+Line 03/04:
+The '-m/--mirrors' option is only relevant to RAID1 and will be used just like
+it is today for DM mirroring.  For all other RAID types, -i/--stripes and
+-I/--stripesize are relevant.  The former will specify the number of data
+devices that will be used for striping.  For example, if the user specifies
+'--type raid0 -i 3', then 3 devices are needed.  If the user specifies
+'--type raid6 -i 3', then 5 devices are needed.  The -I/--stripesize may be
+confusing to MD users, as they use the term "chunksize".  I think they will
+adapt without issue and I don't wish to create a conflict with the term
+"chunksize" that we use for snapshots.
+
+Line 05/06/07:
+I'm still not clear on how to specify these options.  Some are easier than
+others.  '--writemostly' is particularly hard because it involves specifying
+which devices shall be 'write-mostly' and thus, also have 'max-write-behind'
+applied to them.  It has been suggested that a '--readmostly'/'--readfavored'
+or similar option could be introduced as a way to specify a primary disk vs.
+specifying all the non-primary disks via '--writemostly'.  I like this idea,
+but haven't come up with a good name yet.  Thus, these will remain
+unimplemented until future specification.
+
+Line 09/10/11:
+These are familiar.
+
+Further creation related ideas:
+Today, you can specify '--type mirror' without an '-m/--mirrors' argument
+necessary.  The number of devices defaults to two (and the log defaults to
+'disk').  A similar thing should happen with the RAID types.  All of them
+should default to having two data devices unless otherwise specified.  This
+would mean a total number of 2 devices for RAID 0/1, 3 devices for RAID 4/5,
+and 4 devices for RAID 6/10.
+
+
+***************** CONVERTING A RAID DEVICE ******************
+
+01: lvconvert [--type <RAID type>] \
+02:          [-R/--regionsize <size>] \
+03:          [-i/--stripes <#>] [-I,--stripesize <size>] \
+04:          [-m/--mirrors <#>] \
+05:          [--merge]
+06:          [--splitmirrors <#> [--trackchanges]] \
+07:          [--replace <sub_lv|device>] \
+08:          [--[min|max]recoveryrate <kB/sec/disk>] \
+09:          [--stripecache <size>] \
+10:          [--writemostly <devices>] \
+11:          [--maxwritebehind <size>] \
+12:          vg/lv
+13:          [devices]
+
+lvconvert should work exactly as it does now when dealing with mirrors -
+even if(when) we switch to MD RAID1.  Of course, there are no plans to
+allow the presense of the metadata area to be configurable (e.g. --corelog).
+It will be simple enough to detect if the LV being up/down-converted is
+new or old-style mirroring.
+
+If we choose to use MD RAID0 as well, it will be possible to change the
+number of stripes and the stripesize.  It is therefore conceivable to see
+something like, 'lvconvert -i +1 vg/lv'.
+
+Line 01:
+It is possible to change the RAID type of an LV - even if that LV is already
+a RAID device of a different type.  For example, you could change from
+RAID4 to RAID5 or RAID5 to RAID6.
+
+Line 02/03/04:
+These are familiar options - all of which would now be available as options
+for change.  (However, it'd be nice if we didn't have regionsize in there.
+It's simple on the kernel side, but is just an extra - often unecessary -
+parameter to many functions in the LVM codebase.)
+
+Line 05:
+This option is used to merge an LV back into a RAID1 array - provided it was
+split for temporary read-only use by '--splitmirrors 1 --trackchanges'.
+
+Line 06:
+The '--splitmirrors <#>' argument should be familiar from the "mirror" segment
+type.  It allows RAID1 images to be split from the array to form a new LV.
+Either the original LV or the split LV - or both - could become a linear LV as
+a result.  If the '--trackchanges' argument is specified in addition to
+'--splitmirrors', an LV will be split from the array.  It will be read-only.
+This operation does not change the original array - except that it uses an empty
+slot to hold the position of the split LV which it expects to return in the
+future (see the '--merge' argument).  It tracks any changes that occur to the
+array while the slot is kept in reserve.  If the LV is merged back into the
+array, only the changes are resync'ed to the returning image.  Repeating the
+'lvconvert' operation without the '--trackchanges' option will complete the
+split of the LV permanently.
+
+Line 07:
+This option allows the user to specify a sub_lv (e.g. a mirror image) or
+a particular device for replacement.  The device (or all the devices in
+the sub_lv) will be removed and replaced with different devices from the
+VG.
+
+Line 08/09/10/11:
+It should be possible to alter these parameters of a RAID device.  As with
+lvcreate, however, I'm not entirely certain how to best define some of these.
+We don't need all the capabilities at once though, so it isn't a pressing
+issue.
+
+Line 12:
+The LV to operate on.
+
+Line 13:
+Devices that are to be used to satisfy the conversion request.  If the
+operation removes devices or splits a mirror, then the devices specified
+form the list of candidates for removal.  If the operation adds or replaces
+devices, then the devices specified form the list of candidates for allocation.
+
+
+
+###############################################
+# Chapter 2: LVM RAID internal representation #
+###############################################
+
+The internal representation is somewhat like mirroring, but with alterations
+for the different metadata components.  LVM mirroring has a single log LV,
+but RAID will have one for each data device.  Because of this, I've added a
+new 'areas' list to the 'struct lv_segment' - 'meta_areas'.  There is exactly
+a one-to-one relationship between 'areas' and 'meta_areas'.  The 'areas' array
+still holds the data sub-lv's (similar to mirroring), while the 'meta_areas'
+array holds the metadata sub-lv's (akin to the mirroring log device).
+
+The sub_lvs will be named '%s_rimage_%d' instead of '%s_mimage_%d' as it is
+for mirroring, and '%s_rmeta_%d' instead of '%s_mlog'.  Thus, you can imagine
+an LV named 'foo' with the following layout:
+foo
+[foo's lv_segment]
+|
+|-> foo_rimage_0 (areas[0])
+|   [foo_rimage_0's lv_segment]
+|-> foo_rimage_1 (areas[1])
+|   [foo_rimage_1's lv_segment]
+|
+|-> foo_rmeta_0 (meta_areas[0])
+|   [foo_rmeta_0's lv_segment]
+|-> foo_rmeta_1 (meta_areas[1])
+|   [foo_rmeta_1's lv_segment]
+
+LVM Meta-data format
+====================
+The RAID format will need to be able to store parameters that are unique to
+RAID and unique to specific RAID sub-devices.  It will be modeled after that
+of mirroring.
+
+Here is an example of the mirroring layout:
+lv {
+       id = "agL1vP-1B8Z-5vnB-41cS-lhBJ-Gcvz-dh3L3H"
+       status = ["READ", "WRITE", "VISIBLE"]
+       flags = []
+       segment_count = 1
+
+       segment1 {
+               start_extent = 0
+               extent_count = 125      # 500 Megabytes
+
+               type = "mirror"
+               mirror_count = 2
+               mirror_log = "lv_mlog"
+               region_size = 1024
+
+               mirrors = [
+                       "lv_mimage_0", 0,
+                       "lv_mimage_1", 0
+               ]
+       }
+}
+
+The real trick is dealing with the metadata devices.  Mirroring has an entry,
+'mirror_log', in the top-level segment.  This won't work for RAID because there
+is a one-to-one mapping between the data devices and the metadata devices.  The
+mirror devices are layed-out in sub-device/le pairs.  The 'le' parameter is
+redundant since it will always be zero.  So for RAID, I have simple put the
+metadata and data devices in pairs without the 'le' parameter.
+
+RAID metadata:
+lv {
+       id = "EnpqAM-5PEg-i9wB-5amn-P116-1T8k-nS3GfD"
+       status = ["READ", "WRITE", "VISIBLE"]
+       flags = []
+       segment_count = 1
+
+       segment1 {
+               start_extent = 0
+               extent_count = 125      # 500 Megabytes
+
+               type = "raid1"
+               device_count = 2
+               region_size = 1024
+
+               raids = [
+                       "lv_rmeta_0", "lv_rimage_0",
+                       "lv_rmeta_1", "lv_rimage_1",
+               ]
+       }
+}
+
+The metadata also must be capable of representing the various tunables.  We
+already have a good example for one from mirroring, region_size.
+'max_write_behind', 'stripe_cache', and '[min|max]_recovery_rate' could also
+be handled in this way.  However, 'write_mostly' cannot be handled in this
+way, because it is a characteristic associated with the sub_lvs, not the
+array as a whole.  In these cases, the status field of the sub-lv's themselves
+will hold these flags - the meaning being only useful in the larger context.
+
+
+##############################################
+# Chapter 3: LVM RAID implementation details #
+##############################################
+
+New Segment Type(s)
+===================
+I've created a new file 'lib/raid/raid.c' that will handle the various different
+RAID types.  While there will be a unique segment type for each RAID variant,
+they will all share a common backend - segtype_handler functions and
+segtype->flags = SEG_RAID.
+
+I'm also adding a new field to 'struct segment_type', parity_devs.  For every
+segment_type except RAID4/5/6, this will be 0.  This field facilitates in
+allocation and size calculations.  For example, the lvcreate for RAID5 would
+look something like:
+~> lvcreate --type raid5 -L 30G -i 3 -n my_raid5 my_vg
+or
+~> lvcreate --type raid5 -n my_raid5 my_vg /dev/sd[bcdef]1
+
+In the former case, the stripe count (3) and device size are computed, and
+then 'segtype->parity_devs' extra devices are allocated of the same size.  In
+the latter case, the number of PVs is determined and 'segtype->parity_devs' is
+subtracted off to determine the number of stripes.
+
+This should also work in the case of RAID10 and doing things in this manor
+should not affect the way size is calculated via the area_multiple.
+
+Allocation
+==========
+When a RAID device is created, metadata LVs must be created along with the
+data LVs that will ultimately compose the top-level RAID array.  For the
+foreseeable future, the metadata LVs must reside on the same device as (or
+at least one of the devices that compose) the data LV.  We use this property
+to simplify the allocation process.  Rather than allocating for the data LVs
+and then asking for a small chunk of space on the same device (or the other
+way around), we simply ask for the aggregate size of the data LV plus the
+metadata LV.  Once we have the space allocated, we divide it between the
+metadata and data LVs.  This also greatly simplifies the process of finding
+parallel space for all the data LVs that will compose the RAID array.  When
+a RAID device is resized, we will not need to take the metadata LV into
+account, because it will already be present.
+
+Apart from the metadata areas, the other unique characteristic of RAID
+devices is the parity device count.  The number of parity devices does nothing
+to the calculation of size-per-device.  The 'area_multiple' means nothing
+here.  The parity devices will simply be the same size as all the other devices
+and will also require a metadata LV (i.e. it is treated no differently than
+the other devices).
+
+Therefore, to allocate space for RAID devices, we need to know two things:
+1) how many parity devices are required and 2) does an allocated area need to
+be split out for the metadata LVs after finding the space to fill the request.
+We simply add these two fields to the 'alloc_handle' data structure as,
+'parity_count' and 'alloc_and_split_meta'.  These two fields get set in
+'_alloc_init'.   The 'segtype->parity_devs' holds the number of parity
+drives and can be directly copied to 'ah->parity_count' and
+'alloc_and_split_meta' is set when a RAID segtype is detected and
+'metadata_area_count' has been specified.  With these two variables set, we
+can calculate how many allocated areas we need.  Also, in the routines that
+find the actual space, they stop not when they have found ah->area_count but
+when they have found (ah->area_count + ah->parity_count).
+
+Conversion
+==========
+RAID -> RAID, adding images
+---------------------------
+When adding images to a RAID array, metadata and data components must be added
+as a pair.  It is best to perform as many operations as possible before writing
+new LVM metadata.  This allows us to error-out without having to unwind any
+changes.  It also makes things easier if the machine should crash during a
+conversion operation.  Thus, the actions performed when adding a new image are:
+        1) Allocate the required number of metadata/data pairs using the method
+          describe above in 'Allocation' (i.e. find the metadata/data space
+          as one unit and split the space between them after found - this keeps
+          them together on the same device).
+       2) Form the metadata/data LVs from the allocated space (leave them
+          visible) - setting required RAID_[IMAGE | META] flags as appropriate.
+       3) Write the LVM metadata
+       4) Activate and clear the metadata LVs.  The clearing of the metadata
+          requires the LVM metadata be written (step 3) and is a requirement
+          before adding the new metadata LVs to the array.  If the metadata
+          is not cleared, it carry residual superblock state from a previous
+          array the device may have been part of.
+       5) Deactivate new sub-LVs and set them "hidden".
+       6) expand the 'first_seg(raid_lv)->areas' and '->meta_areas' array
+          for inclusion of the new sub-LVs
+       7) Add new sub-LVs and update 'first_seg(raid_lv)->area_count'
+       8) Commit new LVM metadata
+Failure during any of these steps will not affect the original RAID array.  In
+the worst scenario, the user may have to remove the new sub-LVs that did not
+yet make it into the array.
+
+RAID -> RAID, removing images
+-----------------------------
+To remove images from a RAID, the metadata/data LV pairs must be removed
+together.  This is pretty straight-forward, but one place where RAID really
+differs from the "mirror" segment type is how the resulting "holes" are filled.
+When a device is removed from a "mirror" segment type, it is identified, moved
+to the end of the 'mirrored_seg->areas' array, and then removed.  This action
+causes the other images to shift down and fill the position of the device which
+was removed.  While "raid1" could be handled in this way, the other RAID types
+could not be - it would corrupt the ordering of the data on the array.  Thus,
+when a device is removed from a RAID array, the corresponding metadata/data
+sub-LVs are removed from the 'raid_seg->meta_areas' and 'raid_seg->areas' arrays.
+The slot in these 'lv_segment_area' arrays are set to 'AREA_UNASSIGNED'.  RAID
+is perfectly happy to construct a DM table mapping with '- -' if it comes across
+area assigned in such a way.  The pair of dashes is a valid way to tell the RAID
+kernel target that the slot should be considered empty.  So, we can remove
+devices from a RAID array without affecting the correct operation of the RAID.
+(It also becomes easy to replace the empty slots properly if a spare device is
+available.)  In the case of RAID1 device removal, the empty slot can be safely
+eliminated.  This is done by shifting the higher indexed devices down to fill
+the slot.  Even the names of the images will be renamed to properly reflect
+their index in the array.  Unlike the "mirror" segment type, you will never have
+an image named "*_rimage_1" occupying the index position 0.
+
+As with adding images, removing images holds off on commiting LVM metadata
+until all possible changes have been made.  This reduces the likelyhood of bad
+intermediate stages being left due to a failure of operation or machine crash.
+
+RAID1 '--splitmirrors', '--trackchanges', and '--merge' operations
+------------------------------------------------------------------
+This suite of operations is only available to the "raid1" segment type.
+
+Splitting an image from a RAID1 array is almost identical to the removal of
+an image described above.  However, the metadata LV associated with the split
+image is removed and the data LV is kept and promoted to a top-level device.
+(i.e.  It is made visible and stripped of its RAID_IMAGE status flags.)
+
+When the '--trackchanges' option is given along with the '--splitmirrors'
+argument, the metadata LV is left as part of the original array.  The data LV
+is set as 'VISIBLE' and read-only (~LVM_WRITE).  When the array DM table is
+being created, it notices the read-only, VISIBLE nature of the sub-LV and puts
+in the '- -' sentinel.  Only a single image can be split from the mirror and
+the name of the sub-LV cannot be changed.  Unlike '--splitmirrors' on its own,
+the '--name' argument must not be specified.  Therefore, the name of the newly
+split LV will remain the same '<lv>_rimage_<N>', where 'N' is the index of the
+slot in the array for which it is associated.
+
+When an LV which was split from a RAID1 array with the '--trackchanges' option
+is merged back into the array, its read/write status is restored and it is
+set as "hidden" again.  Recycling the array (suspend/resume) restores the sub-LV
+to its position in the array and begins the process of sync'ing the changes that
+were made since the time it was split from the array.
+
+RAID device replacement with '--replace'
+----------------------------------------
+This option is available to all RAID segment types.
+
+The '--replace' option can be used to remove a particular device from a RAID
+logical volume and replace it with a different one in one action (CLI command).
+The device device to be removed is specified as the argument to the '--replace'
+option.  This option can be specified more than once in a single command,
+allowing multiple devices to be replaced at the same time - provided the RAID
+logical volume has the necessary redundancy to allow the action.  The devices
+to be used as replacements can also be specified in the command; similar to the
+way allocatable devices are specified during an up-convert.
+
+Example> lvconvert --replace /dev/sdd1 --replace /dev/sde1 vg/lv /dev/sd[bc]1
+
+RAID '--repair'
+---------------
+This 'lvconvert' option is available to all RAID segment types and is described
+under "RAID Fault Handling".
+
+
+RAID Fault Handling
+===================
+RAID is not like traditional LVM mirroring (i.e. the "mirror" segment type).
+LVM mirroring required failed devices to be removed or the logical volume would
+simply hang.  RAID arrays can keep on running with failed devices.  In fact, for
+RAID types other than RAID1 removing a device would mean substituting an error
+target or converting to a lower level RAID (e.g. RAID6 -> RAID5, or RAID4/5 to
+RAID0).  Therefore, rather than removing a failed device unconditionally, the
+user has a couple of options to choose from.
+
+The automated response to a device failure is handled according to the user's
+preference defined in lvm.conf:activation.raid_fault_policy.  The options are:
+    # "warn"    - Use the system log to warn the user that a device in the RAID
+    #             logical volume has failed.  It is left to the user to run
+    #             'lvconvert --repair' manually to remove or replace the failed
+    #             device.  As long as the number of failed devices does not
+    #             exceed the redundancy of the logical volume (1 device for
+    #             raid4/5, 2 for raid6, etc) the logical volume will remain
+    #             usable.
+    #
+    # "remove"  - NOT CURRENTLY IMPLEMENTED OR DOCUMENTED IN example.conf.in.
+    #             Remove the failed device and reduce the RAID logical volume
+    #             accordingly.  If a single device dies in a 3-way mirror,
+    #             remove it and reduce the mirror to 2-way.  If a single device
+    #             dies in a RAID 4/5 logical volume, reshape it to a striped
+    #             volume, etc - RAID 6 -> RAID 4/5 -> RAID 0.  If devices
+    #             cannot be removed for lack of redundancy, fail.
+    #             THIS OPTION CANNOT YET BE IMPLEMENTED BECAUSE RESHAPE IS NOT
+    #             YET SUPPORTED IN linux/drivers/md/dm-raid.c.  The superblock
+    #             does not yet hold enough information to support reshaping.
+    #
+    # "allocate" - Attempt to use any extra physical volumes in the volume
+    #             group as spares and replace faulty devices.
+
+If manual intervention is taken, either in response to the automated solution's
+"warn" mode or simply because dmeventd hadn't run, then the user can call
+'lvconvert --repair vg/lv' and follow the prompts.  They will be prompted
+whether or not to replace the device and cause a full recovery of the failed
+device.
+
+If replacement is chosen via the manual method or "allocate" is the policy taken
+by the automated response, then 'lvconvert --replace' is the mechanism used to
+attempt the replacement of the failed device.
+
+'vgreduce --removemissing' is ineffectual at repairing RAID logical volumes.  It
+will remove the failed device, but the RAID logical volume will simply continue
+to operate with an <unknown> sub-LV.  The user should clear the failed device
+with 'lvconvert --repair'.
index fa30c0c27420d937ee7b2f36003c64f095d91145..53b447eac6bb890ad8aeefee859cc9ed7921a549 100644 (file)
@@ -15,6 +15,12 @@ from (e.g. a power failure, intermittent network outage, block
 relocation, etc).  The policies for handling both types of failures
 is described herein.
 
+Users need to be aware that there are two implementations of RAID1 in LVM.
+The first is defined by the "mirror" segment type.  The second is defined by
+the "raid1" segment type.  The characteristics of each of these are defined
+in lvm.conf under 'mirror_segtype_default' - the configuration setting used to
+identify the default RAID1 implementation used for LVM operations.
+
 Available Operations During a Device Failure
 --------------------------------------------
 When there is a device failure, LVM behaves somewhat differently because
@@ -51,30 +57,36 @@ are as follows:
   a linear, stripe, or snapshot device is located on the failed device
   the command will not proceed without a '--force' option.  The result
   of using the '--force' option is the entire removal and complete
-  loss of the non-redundant logical volume.  Once this operation is
-  complete, the volume group will again have a complete and consistent
-  view of the devices it contains.  Thus, all operations will be
-  permitted - including creation, conversion, and resizing operations.
+  loss of the non-redundant logical volume.  If an image or metadata area
+  of a RAID logical volume is on the failed device, the sub-LV affected is
+  replace with an error target device - appearing as <unknown> in 'lvs'
+  output.  RAID logical volumes cannot be completely repaired by vgreduce -
+  'lvconvert --repair' (listed below) must be used.  Once this operation is
+  complete on volume groups not containing RAID logical volumes, the volume
+  group will again have a complete and consistent view of the devices it
+  contains.  Thus, all operations will be permitted - including creation,
+  conversion, and resizing operations.  It is currently the preferred method
+  to call 'lvconvert --repair' on the individual logical volumes to repair
+  them followed by 'vgreduce --removemissing' to extract the physical volume's
+  representation in the volume group.
 
 - 'lvconvert --repair <VG/LV>':  This action is designed specifically
-  to operate on mirrored logical volumes.  It is used on logical volumes
-  individually and does not remove the faulty device from the volume
-  group.  If, for example, a failed device happened to contain the
-  images of four distinct mirrors, it would be necessary to run
-  'lvconvert --repair' on each of them.  The ultimate result is to leave
-  the faulty device in the volume group, but have no logical volumes
-  referencing it.  In addition to removing mirror images that reside
-  on failed devices, 'lvconvert --repair' can also replace the failed
-  device if there are spare devices available in the volume group.  The
-  user is prompted whether to simply remove the failed portions of the
-  mirror or to also allocate a replacement, if run from the command-line.
-  Optionally, the '--use-policies' flag can be specified which will
-  cause the operation not to prompt the user, but instead respect
+  to operate on individual logical volumes.  If, for example, a failed
+  device happened to contain the images of four distinct mirrors, it would
+  be necessary to run 'lvconvert --repair' on each of them.  The ultimate
+  result is to leave the faulty device in the volume group, but have no logical
+  volumes referencing it.  (This allows for 'vgreduce --removemissing' to
+  removed the physical volumes cleanly.)  In addition to removing mirror or
+  RAID images that reside on failed devices, 'lvconvert --repair' can also
+  replace the failed device if there are spare devices available in the
+  volume group.  The user is prompted whether to simply remove the failed
+  portions of the mirror or to also allocate a replacement, if run from the
+  command-line.  Optionally, the '--use-policies' flag can be specified which
+  will cause the operation not to prompt the user, but instead respect
   the policies outlined in the LVM configuration file - usually,
-  /etc/lvm/lvm.conf.  Once this operation is complete, mirrored logical
-  volumes will be consistent and I/O will be allowed to continue.
-  However, the volume group will still be inconsistent -  due to the
-  refernced-but-missing device/PV - and operations will still be
+  /etc/lvm/lvm.conf.  Once this operation is complete, the logical volumes
+  will be consistent.  However, the volume group will still be inconsistent -
+  due to the refernced-but-missing device/PV - and operations will still be
   restricted to the aformentioned actions until either the device is
   restored or 'vgreduce --removemissing' is run.
 
@@ -98,13 +110,15 @@ following possible exceptions exist:
 
 Automated Target Response to Failures:
 --------------------------------------
-The only LVM target type (i.e. "personality") that has an automated
-response to failures is a mirrored logical volume.  The other target
+The only LVM target types (i.e. "personalities") that have an automated
+response to failures are the mirror and RAID logical volumes.  The other target
 types (linear, stripe, snapshot, etc) will simply propagate the failure.
 [A snapshot becomes invalid if its underlying device fails, but the
 origin will remain valid - presuming the origin device has not failed.]
-There are three types of errors that a mirror can suffer - read, write,
-and resynchronization errors.  Each is described in depth below.
+
+Starting with the "mirror" segment type, there are three types of errors that
+a mirror can suffer - read, write, and resynchronization errors.  Each is
+described in depth below.
 
 Mirror read failures:
 If a mirror is 'in-sync' (i.e. all images have been initialized and
@@ -184,38 +198,5 @@ command are set in the LVM configuration file.  They are:
   choice of when to incure the extra performance costs of replacing
   the failed image.
 
-TODO...
-The appropriate time to take permanent corrective action on a mirror
-should be driven by policy.  There should be a directive that takes
-a time or percentage argument.  Something like the following:
-- mirror_fault_policy_WHEN = "10sec"/"10%"
-A time value would signal the amount of time to wait for transient
-failures to resolve themselves.  The percentage value would signal the
-amount a mirror could become out-of-sync before the faulty device is
-removed.
-
-A mirror cannot be used unless /some/ corrective action is taken,
-however.  One option is to replace the failed mirror image with an
-error target, forgo the use of 'handle_errors', and simply let the
-out-of-sync regions accumulate and be tracked by the log.  Mirrors
-that have more than 2 images would have to "stack" to perform the
-tracking, as each failed image would have to be associated with a
-log.  If the failure is transient, the device would replace the
-error target that was holding its spot and the log that was tracking
-the deltas would be used to quickly restore the portions that changed.
-
-One unresolved issue with the above scheme is how to know which
-regions of the mirror are out-of-sync when a problem occurs.  When
-a write failure occurs in the kernel, the log will contain those
-regions that are not in-sync.  If the log is a disk log, that log
-could continue to be used to track differences.  However, if the
-log was a core log - or if the log device failed at the same time
-as an image device - there would be no way to determine which
-regions are out-of-sync to begin with as we start to track the
-deltas for the failed image.  I don't have a solution for this
-problem other than to only be able to handle errors in this way
-if conditions are right.  These issues will have to be ironed out
-before proceeding.  This could be another case, where it is better
-to handle failures in the kernel by allowing the kernel to store
-updates in various metadata areas.
-...TODO
+RAID logical volume device failures are handled differently from the "mirror"
+segment type.  Discussion of this can be found in lvm2-raid.txt.
diff --git a/doc/lvmetad_design.txt b/doc/lvmetad_design.txt
new file mode 100644 (file)
index 0000000..3b336ec
--- /dev/null
@@ -0,0 +1,197 @@
+The design of LVMetaD
+=====================
+
+Invocation and setup
+--------------------
+
+The daemon should be started automatically by the first LVM command issued on
+the system, when needed. The usage of the daemon should be configurable in
+lvm.conf, probably with its own section. Say
+
+    lvmetad {
+        enabled = 1 # default
+        autostart = 1 # default
+        socket = "/path/to/socket" # defaults to /var/run/lvmetad or such
+    }
+
+Library integration
+-------------------
+
+When a command needs to access metadata, it currently needs to perform a scan
+of the physical devices available in the system. This is a possibly quite
+expensive operation, especially if many devices are attached to the system. In
+most cases, LVM needs a complete image of the system's PVs to operate
+correctly, so all devices need to be read, to at least determine presence (and
+content) of a PV label. Additional IO is done to obtain or write metadata
+areas, but this is only marginally related and addressed by Dave's
+metadata-balancing work.
+
+In the existing scanning code, a cache layer exists, under
+lib/cache/lvmcache.[hc]. This layer is keeping a textual copy of the metadata
+for a given volume group, in a format_text form, as a character string. We can
+plug the lvmetad interface at this level: in lvmcache_get_vg, which is
+responsible for looking up metadata in a local cache, we can, if the metadata
+is not available in the local cache, query lvmetad. Under normal circumstances,
+when a VG is not cached yet, this operation fails and prompts the caller to
+perform a scan. Under the lvmetad enabled scenario, this would never happen and
+the fall-through would only be activated when lvmetad is disabled, which would
+lead to local cache being populated as usual through a locally executed scan.
+
+Therefore, existing stand-alone (i.e. no lvmetad) functionality of the tools
+would be not compromised by adding lvmetad. With lvmetad enabled, however,
+significant portions of the code would be short-circuited.
+
+Scanning
+--------
+
+Initially (at least), the lvmetad will be not allowed to read disks: it will
+rely on an external program to provide the metadata. In the ideal case, this
+will be triggered by udev. The role of lvmetad is then to collect and maintain
+an accurate (up to the data it has received) image of the VGs available in the
+system. I imagine we could extend the pvscan command (or add a new one, say
+lvmetad_client, if pvscan is found to be inappropriate):
+
+    $ pvscan --cache /dev/foo
+    $ pvscan --cache --remove /dev/foo
+
+These commands would simply read the label and the MDA (if applicable) from the
+given PV and feed that data to the running lvmetad, using
+lvmetad_{add,remove}_pv (see lvmetad_client.h).
+
+We however need to ensure a couple of things here:
+
+1) only LVM commands ever touch PV labels and VG metadata
+2) when a device is added or removed, udev fires a rule to notify lvmetad
+
+While the latter is straightforward, there are issues with the first. We
+*might* want to invoke the dreaded "watch" udev rule in this case, however it
+ends up being implemented. Of course, we can also rely on the sysadmin to be
+reasonable and not write over existing LVM metadata without first telling LVM
+to let go of the respective device(s).
+
+Even if we simply ignore the problem, metadata write should fail in these
+cases, so the admin should be unable to do substantial damage to the system. If
+there were active LVs on top of the vanished PV, they are in trouble no matter
+what happens there.
+
+Incremental scan
+----------------
+
+There are some new issues arising with the "udev" scan mode. Namely, the
+devices of a volume group will be appearing one by one. The behaviour in this
+case will be very similar to the current behaviour when devices are missing:
+the volume group, until *all* its physical volumes have been discovered and
+announced by udev, will be in a state with some of its devices flagged as
+MISSING_PV. This means that the volume group will be, for most purposes,
+read-only until it is complete and LVs residing on yet-unknown PVs won't
+activate without --partial. Under usual circumstances, this is not a problem
+and the current code for dealing with MISSING_PVs should be adequate.
+
+However, the code for reading volume groups from disks will need to be adapted,
+since it currently does not work incrementally. Such support will need to track
+metadata-less PVs that have been encountered so far and to provide a way to
+update an existing volume group. When the first PV with metadata of a given VG
+is encountered, the VG is created in lvmetad (probably in the form of "struct
+volume_group") and it is assigned any previously cached metadata-less PVs it is
+referencing. Any PVs that were not yet encountered will be marked as MISSING_PV
+in the "struct volume_group". Upon scanning a new PV, if it belongs to any
+already-known volume group, this PV is checked for consistency with the already
+cached metadata (in a case of mismatch, the VG needs to be recovered or
+declared conflicted), and is subsequently unmarked MISSING_PV. Care need be
+taken not to unmark MISSING_PV on PVs that have this flag in their persistent
+metadata, though.
+
+The most problematic aspect of the whole design may be orphan PVs. At any given
+point, a metadata-less PV may appear orphaned, if a PV of its VG with metadata
+has not been scanned yet. Eventually, we will have to decide that this PV is
+really an orphan and enable its usage for creating or extending VGs. In
+practice, the decision might be governed by a timeout or assumed immediately --
+the former case is a little safer, the latter is probably more transparent. I
+am not very keen on using timeouts and we can probably assume that the admin
+won't blindly try to re-use devices in a way that would trip up LVM in this
+respect. I would be in favour of just assuming that metadata-less VGs with no
+known referencing VGs are orphans -- after all, this is the same approach as we
+use today. The metadata balancing support may stress this a bit more than the
+usual contemporary setups do, though.
+
+Automatic activation
+--------------------
+
+It may also be prudent to provide a command that will block until a volume
+group is complete, so that scripts can reliably activate/mount LVs and such. Of
+course, some PVs may never appear, so a timeout is necessary. Again, this is
+something not handled by current tools, but may become more important in
+future. It probably does not need to be implemented right away though.
+
+The other aspect of the progressive VG assembly is automatic activation. The
+currently only problem with that is that we would like to avoid having
+activation code in lvmetad, so we would prefer to fire up an event of some sort
+and let someone else handle the activation and whatnot.
+
+Cluster support
+---------------
+
+When working in a cluster, clvmd integration will be necessary: clvmd will need
+to instruct lvmetad to re-read metadata as appropriate due to writes on remote
+hosts. Overall, this is not hard, but the devil is in the details. I would
+possibly disable lvmetad for clustered volume groups in the first phase and
+only proceed when the local mode is robust and well tested.
+
+Protocol & co.
+--------------
+
+I expect a simple text-based protocol executed on top of an Unix Domain Socket
+to be the communication interface for lvmetad. Ideally, the requests and
+replies will be well-formed "config file" style strings, so we can re-use
+existing parsing infrastructure.
+
+Since we already have two daemons, I would probably look into factoring some
+common code for daemon-y things, like sockets, communication (including thread
+management) and maybe logging and re-using it in all the daemons (clvmd,
+dmeventd and lvmetad). This shared infrastructure should live under
+daemons/common, and the existing daemons shall be gradually migrated to the
+shared code.
+
+Future extensions
+-----------------
+
+The above should basically cover the use of lvmetad as a cache-only
+daemon. Writes could still be executed locally, and the new metadata version
+can be provided to lvmetad through the socket the usual way. This is fairly
+natural and in my opinion reasonable. The lvmetad acts like a cache that will
+hold metadata, no more no less.
+
+Above this, there is a couple of things that could be worked on later, when the
+above basic design is finished and implemented.
+
+_Metadata writing_: We may want to support writing new metadata through
+lvmetad. This may or may not be a better design, but the write itself should be
+more or less orthogonal to the rest of the story outlined above.
+
+_Locking_: Other than directing metadata writes through lvmetad, one could
+conceivably also track VG/LV locking through the same.
+
+_Clustering_: A deeper integration of lvmetad with clvmd might be possible and
+maybe desirable. Since clvmd communicates over the network with other clvmd
+instances, this could be extended to metadata exchange between lvmetad's,
+further cutting down scanning costs. This would combine well with the
+write-through-lvmetad approach.
+
+Testing
+-------
+
+Since (at least bare-bones) lvmetad has no disk interaction and is fed metadata
+externally, it should be very amenable to automated testing. We need to provide
+a client that can feed arbitrary, synthetic metadata to the daemon and request
+the data back, providing reasonable (nearly unit-level) testing infrastructure.
+
+Battle plan & code layout
+=========================
+
+- config_tree from lib/config needs to move to libdm/
+- daemon/common *client* code can go to libdm/ as well (say
+  libdm/libdm-daemon.{h,c} or such)
+- daemon/common *server* code stays, is built in daemon/ toplevel as a static
+  library, say libdaemon-common.a
+- daemon/lvmetad *client* code goes to lib/lvmetad
+- daemon/lvmetad *server* code stays (links in daemon/libdaemon_common.a)
index 5a3f520c15989aa2856e2ec1a6cee5456fd0e62a..b66e0ecd3a735beb575fb25498e9841d7dc82148 100644 (file)
@@ -79,13 +79,13 @@ Usage Examples
 
   lvm.conf:  (Identical on every machine - global settings)
     tags {
-      hostname_tags = 1
+      hosttags = 1
     }
 
   From any machine in the cluster, add db1 to the list of machines that
   activate vg1/lvol2:
 
-  lvchange --tag @db1 vg1/lvol2
+  lvchange --addtag @db1 vg1/lvol2
   (followed by lvchange -ay to actually activate it)
 
 
@@ -98,10 +98,10 @@ Usage Examples
 
   Option (i) - centralised admin, static configuration replicated between hosts  
     # Add @database tag to vg1's metadata
-    vgchange --tag @database vg1
+    vgchange --addtag @database vg1
 
     # Add @fileserver tag to vg2's metadata
-    vgchange --tag @fileserver vg2
+    vgchange --addtag @fileserver vg2
 
     lvm.conf:  (Identical on every machine)
       tags {
@@ -122,17 +122,17 @@ Usage Examples
       }
   
   In the event of the fileserver host going down, vg2 can be brought up
-  on fsb1 by running *on any node* 'vgchange --tag @fileserverbackup vg2'
+  on fsb1 by running *on any node* 'vgchange --addtag @fileserverbackup vg2'
   followed by 'vgchange -ay vg2'
   
   
   Option (ii) - localised admin & configuation
   (i.e. each host holds *locally* which classes of volumes to activate)
     # Add @database tag to vg1's metadata
-    vgchange --tag @database vg1
+    vgchange --addtag @database vg1
   
     # Add @fileserver tag to vg2's metadata
-    vgchange --tag @fileserver vg2
+    vgchange --addtag @fileserver vg2
   
     lvm.conf:  (Identical on every machine - global settings)
       tags {
diff --git a/doc/udev_assembly.txt b/doc/udev_assembly.txt
new file mode 100644 (file)
index 0000000..6186402
--- /dev/null
@@ -0,0 +1,83 @@
+Automatic device assembly by udev
+=================================
+
+We want to asynchronously assemble and activate devices as their components
+become available. Eventually, the complete storage stack should be covered,
+including: multipath, cryptsetup, LVM, mdadm. Each of these can be addressed
+more or less separately.
+
+The general plan of action is to simply provide udev rules for each of the
+device "type": for MD component devices, PVs, LUKS/crypto volumes and for
+multipathed SCSI devices. There's no compelling reason to have a daemon do these
+things: all systems that actually need to assemble multiple devices into a
+single entity already either support incremental assembly or will do so shortly.
+
+Whenever in this document we talk about udev rules, these may include helper
+programs that implement a multi-step process. In many cases, it can be expected
+that the functionality can be implemented in couple lines of shell (or couple
+hundred of C).
+
+Multipath
+---------
+
+For multipath, we will need to rely on SCSI IDs for now, until we have a better
+scheme of things, since multipath devices can't be identified until the second
+path appears, and unfortunately we need to decide whether a device is multipath
+when the *first* path appears. Anyway, the multipath folks need to sort this
+out, but it shouldn't bee too hard. Just bring up multipathing on anything that
+appears and is set up for multipathing.
+
+LVM
+---
+
+For LVM, the crucial piece of the puzzle is lvmetad, which allows us to build up
+VGs from PVs as they appear, and at the same time collect information on what is
+already available. A command, pvscan --cache is expected to be used to
+implement udev rules. It is relatively easy to make this command print out a
+list of VGs (and possibly LVs) that have been made available by adding any
+particular device to the set of visible devices. In othe words, udev says "hey,
+/dev/sdb just appeared", calls pvscan --cache, which talks to lvmetad, which
+says "cool, that makes vg0 complete". Pvscan takes this info and prints it out,
+and the udev rule can then somehow decide whether anything needs to be done
+about this "vg0". Presumably a table of devices that need to be activated
+automatically is made available somewhere in /etc (probably just a simple list
+of volume groups or logical volumes, given by name or UUID, globbing
+possible). The udev rule can then consult this file.
+
+Cryptsetup
+----------
+
+This may be the trickiest of the lot: the obvious hurdle here is that crypto
+volumes need to somehow obtain a key (passphrase, physical token or such),
+meaning there is interactivity involved. On the upside, dm-crypt is a 1:1
+system: one encrypted device results in one decrypted device, so no assembly or
+notification needs to be done. While interactivity is a challenge, there are at
+least partial solutions around. (TODO: Milan should probably elaborate here.)
+
+(For LUKS devices, these can probably be detected automatically. I suppose that
+non-LUKS devices can be looked up in crypttab by the rule, to decide what is the
+appropriate action to take.)
+
+MD
+--
+
+Fortunately, MD (namely mdadm) already comes with a mechanism for incremental
+assembly (mdadm -I or such). We can assume that this fits with the rest of stack
+nicely.
+
+
+Filesystem &c. discovery
+========================
+
+Considering other requirements that exist for storage systems (namely
+large-scale storage deployments), it is absolutely not feasible to have the
+system hunt automatically for filesystems based on their UUIDs. In a number of
+cases, this could mean activating tens of thousands of volumes. On small
+systems, asking for all volumes to be brought up automatically is probably the
+best route anyway, and once all storage devices are activated, scanning for
+filesystems is no different from today.
+
+In effect, no action is required on this count: only filesystems that are
+available on already active devices can be mounted by their UUID. Activating
+volumes by naming a filesystem UUID is useless, since to read the UUID the
+volume needs to be active first.
index c16e107d90c9b20aae984d04c4c73036340eb730..e94ff849877093de60eb837bd6850ad9fe645e69 100644 (file)
@@ -1,9 +1,11 @@
 @top_srcdir@/daemons/clvmd/clvm.h
 @top_srcdir@/daemons/dmeventd/libdevmapper-event.h
+@top_srcdir@/daemons/lvmetad/lvmetad-client.h
 @top_srcdir@/liblvm/lvm2app.h
 @top_srcdir@/lib/activate/activate.h
 @top_srcdir@/lib/activate/targets.h
 @top_srcdir@/lib/cache/lvmcache.h
+@top_srcdir@/lib/cache/lvmetad.h
 @top_srcdir@/lib/commands/errors.h
 @top_srcdir@/lib/commands/toolcontext.h
 @top_srcdir@/lib/config/config.h
@@ -16,6 +18,7 @@
 @top_srcdir@/lib/display/display.h
 @top_srcdir@/lib/filters/filter-composite.h
 @top_srcdir@/lib/filters/filter-md.h
+@top_srcdir@/lib/filters/filter-mpath.h
 @top_srcdir@/lib/filters/filter-persistent.h
 @top_srcdir@/lib/filters/filter-regex.h
 @top_srcdir@/lib/filters/filter-sysfs.h
@@ -57,6 +60,9 @@
 @top_srcdir@/lib/report/properties.h
 @top_srcdir@/lib/report/report.h
 @top_srcdir@/lib/uuid/uuid.h
+@top_srcdir@/libdaemon/client/daemon-client.h
+@top_srcdir@/libdaemon/client/daemon-io.h
+@top_srcdir@/libdaemon/client/config-util.h
 @top_srcdir@/libdm/libdevmapper.h
 @top_srcdir@/libdm/misc/dm-ioctl.h
 @top_srcdir@/libdm/misc/dm-logging.h
index 010e8886fe61f76ca49fc3620afeb3aa56f08204..82f700b1018763e44edf8c16422c8b90237c010e 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
-# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
 #
 # This file is part of LVM2.
 #
@@ -32,10 +32,18 @@ ifeq ("@MIRRORS@", "shared")
   SUBDIRS += mirror
 endif
 
+ifeq ("@RAID@", "shared")
+  SUBDIRS += raid
+endif
+
 ifeq ("@REPLICATORS@", "shared")
   SUBDIRS += replicator
 endif
 
+ifeq ("@THIN@", "shared")
+  SUBDIRS += thin
+endif
+
 SOURCES =\
        activate/activate.c \
        cache/lvmcache.c \
@@ -57,6 +65,7 @@ SOURCES =\
        filters/filter-regex.c \
        filters/filter-sysfs.c \
        filters/filter-md.c \
+       filters/filter-mpath.c \
        filters/filter.c \
        format_text/archive.c \
        format_text/archiver.c \
@@ -81,9 +90,11 @@ SOURCES =\
        metadata/pv.c \
        metadata/pv_manip.c \
        metadata/pv_map.c \
+       metadata/raid_manip.c \
        metadata/replicator_manip.c \
        metadata/segtype.c \
        metadata/snapshot_manip.c \
+       metadata/thin_manip.c \
        metadata/vg.c \
        misc/crc.c \
        misc/lvm-exec.c \
@@ -92,7 +103,6 @@ SOURCES =\
        misc/lvm-string.c \
        misc/lvm-wrappers.c \
        misc/lvm-percent.c \
-       misc/util.c \
        mm/memlock.c \
        report/properties.c \
        report/report.c \
@@ -140,10 +150,18 @@ ifeq ("@MIRRORS@", "internal")
   SOURCES += mirror/mirrored.c
 endif
 
+ifeq ("@RAID@", "internal")
+  SOURCES += raid/raid.c
+endif
+
 ifeq ("@REPLICATORS@", "internal")
   SOURCES += replicator/replicator.c
 endif
 
+ifeq ("@THIN@", "internal")
+  SOURCES += thin/thin.c
+endif
+
 ifeq ("@DEVMAPPER@", "yes")
   SOURCES +=\
        activate/dev_manager.c \
@@ -156,6 +174,11 @@ ifeq ("@HAVE_LIBDL@", "yes")
        misc/sharedlib.c
 endif
 
+ifeq ("@BUILD_LVMETAD@", "yes")
+  SOURCES +=\
+       cache/lvmetad.c
+endif
+
 ifeq ("@DMEVENTD@", "yes")
   CLDFLAGS += -L$(top_builddir)/daemons/dmeventd
   LIBS += -ldevmapper-event
@@ -170,7 +193,9 @@ ifeq ($(MAKECMDGOALS),distclean)
        format_pool \
        snapshot \
        mirror \
+       raid \
        replicator \
+       thin \
        locking
 endif
 
index 174f09e731efe472a887fe52b98306eeab6b6f81..185ba5fe301aed529f66838d2f6335534b889b64 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -38,7 +38,7 @@
 
 int lvm1_present(struct cmd_context *cmd)
 {
-       char path[PATH_MAX];
+       static char path[PATH_MAX];
 
        if (dm_snprintf(path, sizeof(path), "%s/lvm/global", cmd->proc_dir)
            < 0) {
@@ -147,31 +147,58 @@ int target_present(struct cmd_context *cmd, const char *target_name,
 {
        return 0;
 }
-int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, unsigned origin_only,
+int lvm_dm_prefix_check(int major, int minor, const char *prefix)
+{
+       return 0;
+}
+int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int use_layer,
            struct lvinfo *info, int with_open_count, int with_read_ahead)
 {
        return 0;
 }
-int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
-                   unsigned origin_only,
+int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
                    struct lvinfo *info, int with_open_count, int with_read_ahead)
 {
        return 0;
 }
+int lv_check_not_in_use(struct cmd_context *cmd __attribute__((unused)),
+                       struct logical_volume *lv, struct lvinfo *info)
+{
+        return 0;
+}
 int lv_snapshot_percent(const struct logical_volume *lv, percent_t *percent)
 {
        return 0;
 }
-int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
+int lv_mirror_percent(struct cmd_context *cmd, const struct logical_volume *lv,
                      int wait, percent_t *percent, uint32_t *event_nr)
 {
        return 0;
 }
-int lvs_in_vg_activated(struct volume_group *vg)
+int lv_raid_percent(const struct logical_volume *lv, percent_t *percent)
+{
+       return 0;
+}
+int lv_thin_pool_percent(const struct logical_volume *lv, int metadata,
+                        percent_t *percent)
+{
+       return 0;
+}
+int lv_thin_percent(const struct logical_volume *lv, int mapped,
+                   percent_t *percent)
 {
        return 0;
 }
-int lvs_in_vg_opened(struct volume_group *vg)
+int lv_thin_pool_transaction_id(const struct logical_volume *lv,
+                               uint64_t *transaction_id)
+{
+       return 0;
+}
+int lvs_in_vg_activated(const struct volume_group *vg)
+{
+       return 0;
+}
+int lvs_in_vg_opened(const struct volume_group *vg)
 {
        return 0;
 }
@@ -181,15 +208,16 @@ int lv_suspend(struct cmd_context *cmd, const char *lvid_s)
        return 1;
 }
 *******/
-int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s)
+int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, unsigned exclusive)
 {
        return 1;
 }
-int lv_resume(struct cmd_context *cmd, const char *lvid_s)
+int lv_resume(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only)
 {
        return 1;
 }
-int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s)
+int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s,
+                       unsigned origin_only, unsigned exclusive, unsigned revert)
 {
        return 1;
 }
@@ -210,28 +238,73 @@ int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exc
 {
        return 1;
 }
-
 int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
 {
        return 1;
 }
-
 int pv_uses_vg(struct physical_volume *pv,
               struct volume_group *vg)
 {
        return 0;
 }
-
 void activation_release(void)
 {
-       return;
 }
-
 void activation_exit(void)
 {
-       return;
 }
 
+int lv_is_active(const struct logical_volume *lv)
+{
+       return 0;
+}
+int lv_is_active_but_not_locally(const struct logical_volume *lv)
+{
+       return 0;
+}
+int lv_is_active_exclusive(const struct logical_volume *lv)
+{
+       return 0;
+}
+int lv_is_active_exclusive_locally(const struct logical_volume *lv)
+{
+       return 0;
+}
+int lv_is_active_exclusive_remotely(const struct logical_volume *lv)
+{
+       return 0;
+}
+
+int lv_check_transient(struct logical_volume *lv)
+{
+       return 1;
+}
+int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv,
+                          const struct lv_activate_opts *laopts, int monitor)
+{
+       return 1;
+}
+/* fs.c */
+void fs_unlock(void)
+{
+}
+/* dev_manager.c */
+#include "targets.h"
+int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
+                  struct dm_tree_node *node, uint32_t start_area,
+                  uint32_t areas)
+{
+        return 0;
+}
+int device_is_usable(struct device *dev)
+{
+        return 0;
+}
+int lv_has_target_type(struct dm_pool *mem, struct logical_volume *lv,
+                      const char *layer, const char *target_type)
+{
+        return 0;
+}
 #else                          /* DEVMAPPER_SUPPORT */
 
 static int _activation = 1;
@@ -255,49 +328,27 @@ int activation(void)
        return _activation;
 }
 
-static int _passes_activation_filter(struct cmd_context *cmd,
-                                    struct logical_volume *lv)
+static int _lv_passes_volumes_filter(struct cmd_context *cmd, struct logical_volume *lv,
+                                    const struct dm_config_node *cn, const char *config_path)
 {
-       const struct config_node *cn;
-       const struct config_value *cv;
+       const struct dm_config_value *cv;
        const char *str;
-       char path[PATH_MAX];
+       static char path[PATH_MAX];
 
-       if (!(cn = find_config_tree_node(cmd, "activation/volume_list"))) {
-               log_verbose("activation/volume_list configuration setting "
-                           "not defined, checking only host tags for %s/%s",
-                           lv->vg->name, lv->name);
-
-               /* If no host tags defined, activate */
-               if (dm_list_empty(&cmd->tags))
-                       return 1;
-
-               /* If any host tag matches any LV or VG tag, activate */
-               if (str_list_match_list(&cmd->tags, &lv->tags, NULL) ||
-                   str_list_match_list(&cmd->tags, &lv->vg->tags, NULL))
-                       return 1;
-
-               log_verbose("No host tag matches %s/%s",
-                           lv->vg->name, lv->name);
-
-               /* Don't activate */
-               return 0;
-       }
-       else
-               log_verbose("activation/volume_list configuration setting "
-                           "defined, checking the list to match %s/%s",
-                           lv->vg->name, lv->name);
+       log_verbose("%s configuration setting defined: "
+                   "Checking the list to match %s/%s",
+                   config_path, lv->vg->name, lv->name);
 
        for (cv = cn->v; cv; cv = cv->next) {
-               if (cv->type != CFG_STRING) {
-                       log_error("Ignoring invalid string in config file "
-                                 "activation/volume_list");
+               if (cv->type != DM_CFG_STRING) {
+                       log_error("Ignoring invalid string in config file %s",
+                                 config_path);
                        continue;
                }
                str = cv->v.str;
                if (!*str) {
-                       log_error("Ignoring empty string in config file "
-                                 "activation/volume_list");
+                       log_error("Ignoring empty string in config file %s",
+                                 config_path);
                        continue;
                }
 
@@ -307,7 +358,7 @@ static int _passes_activation_filter(struct cmd_context *cmd,
                        str++;
                        if (!*str) {
                                log_error("Ignoring empty tag in config file "
-                                         "activation/volume_list");
+                                         "%s", config_path);
                                continue;
                        }
                        /* If any host tag matches any LV or VG tag, activate */
@@ -344,12 +395,66 @@ static int _passes_activation_filter(struct cmd_context *cmd,
                        return 1;
        }
 
-       log_verbose("No item supplied in activation/volume_list configuration "
-                   "setting matches %s/%s", lv->vg->name, lv->name);
+       log_verbose("No item supplied in %s configuration setting "
+                   "matches %s/%s", config_path, lv->vg->name, lv->name);
 
        return 0;
 }
 
+static int _passes_activation_filter(struct cmd_context *cmd,
+                                    struct logical_volume *lv)
+{
+       const struct dm_config_node *cn;
+
+       if (!(cn = find_config_tree_node(cmd, "activation/volume_list"))) {
+               log_verbose("activation/volume_list configuration setting "
+                           "not defined: Checking only host tags for %s/%s",
+                           lv->vg->name, lv->name);
+
+               /* If no host tags defined, activate */
+               if (dm_list_empty(&cmd->tags))
+                       return 1;
+
+               /* If any host tag matches any LV or VG tag, activate */
+               if (str_list_match_list(&cmd->tags, &lv->tags, NULL) ||
+                   str_list_match_list(&cmd->tags, &lv->vg->tags, NULL))
+                       return 1;
+
+               log_verbose("No host tag matches %s/%s",
+                           lv->vg->name, lv->name);
+
+               /* Don't activate */
+               return 0;
+       }
+
+       return _lv_passes_volumes_filter(cmd, lv, cn, "activation/volume_list");
+}
+
+static int _passes_readonly_filter(struct cmd_context *cmd,
+                                  struct logical_volume *lv)
+{
+       const struct dm_config_node *cn;
+
+       if (!(cn = find_config_tree_node(cmd, "activation/read_only_volume_list")))
+               return 0;
+
+       return _lv_passes_volumes_filter(cmd, lv, cn, "activation/read_only_volume_list");
+}
+
+
+int lv_passes_auto_activation_filter(struct cmd_context *cmd, struct logical_volume *lv)
+{
+       const struct dm_config_node *cn;
+
+       if (!(cn = find_config_tree_node(cmd, "activation/auto_activation_volume_list"))) {
+               log_verbose("activation/auto_activation_volume_list configuration setting "
+                           "not defined: All logical volumes will be auto-activated.");
+               return 1;
+       }
+
+       return _lv_passes_volumes_filter(cmd, lv, cn, "activation/auto_activation_volume_list");
+}
+
 int library_version(char *version, size_t size)
 {
        if (!activation())
@@ -379,10 +484,17 @@ int target_version(const char *target_name, uint32_t *maj,
        if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
                return_0;
 
+        if (activation_checks() && !dm_task_enable_checks(dmt))
+                goto_out;
+
        if (!dm_task_run(dmt)) {
                log_debug("Failed to get %s target version", target_name);
                /* Assume this was because LIST_VERSIONS isn't supported */
-               return 1;
+               *maj = 0;
+               *min = 0;
+               *patchlevel = 0;
+               r = 1;
+               goto out;
        }
 
        target = dm_task_get_versions(dmt);
@@ -402,11 +514,39 @@ int target_version(const char *target_name, uint32_t *maj,
        } while (last_target != target);
 
       out:
+       if (r)
+               log_very_verbose("Found %s target "
+                                "v%" PRIu32 ".%" PRIu32 ".%" PRIu32 ".",
+                                target_name, *maj, *min, *patchlevel);
+
        dm_task_destroy(dmt);
 
        return r;
 }
 
+int lvm_dm_prefix_check(int major, int minor, const char *prefix)
+{
+       struct dm_task *dmt;
+       const char *uuid;
+       int r;
+
+       if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
+               return_0;
+
+       if (!dm_task_set_minor(dmt, minor) ||
+           !dm_task_set_major(dmt, major) ||
+           !dm_task_run(dmt) ||
+           !(uuid = dm_task_get_uuid(dmt))) {
+               dm_task_destroy(dmt);
+               return 0;
+       }
+
+       r = strncasecmp(uuid, prefix, strlen(prefix));
+       dm_task_destroy(dmt);
+
+       return r ? 0 : 1;
+}
+
 int module_present(struct cmd_context *cmd, const char *target_name)
 {
        int ret = 0;
@@ -424,7 +564,7 @@ int module_present(struct cmd_context *cmd, const char *target_name)
        argv[1] = module;
        argv[2] = NULL;
 
-       ret = exec_cmd(cmd, argv, NULL);
+       ret = exec_cmd(cmd, argv, NULL, 0);
 #endif
        return ret;
 }
@@ -453,15 +593,35 @@ int target_present(struct cmd_context *cmd, const char *target_name,
 /*
  * Returns 1 if info structure populated, else 0 on failure.
  */
-int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, unsigned origin_only,
+int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int use_layer,
            struct lvinfo *info, int with_open_count, int with_read_ahead)
 {
        struct dm_info dminfo;
+       const char *layer;
 
        if (!activation())
                return 0;
+       /*
+        * If open_count info is requested and we have to be sure our own udev
+        * transactions are finished
+        * For non-clustered locking type we are only interested for non-delete operation
+        * in progress - as only those could lead to opened files
+        */
+       if (with_open_count) {
+               if (locking_is_clustered())
+                       sync_local_dev_names(cmd); /* Wait to have udev in sync */
+               else if (fs_has_non_delete_ops())
+                       fs_unlock(); /* For non clustered - wait if there are non-delete ops */
+       }
 
-       if (!dev_manager_info(lv->vg->cmd->mem, lv, origin_only ? "real" : NULL, with_open_count,
+       if (use_layer && lv_is_thin_pool(lv))
+               layer = "tpool";
+       else if (use_layer && lv_is_origin(lv))
+               layer = "real";
+       else
+               layer = NULL;
+
+       if (!dev_manager_info(lv->vg->cmd->mem, lv, layer, with_open_count,
                              with_read_ahead, &dminfo, &info->read_ahead))
                return_0;
 
@@ -477,8 +637,7 @@ int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, unsigned o
        return 1;
 }
 
-int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
-                   unsigned origin_only,
+int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
                    struct lvinfo *info, int with_open_count, int with_read_ahead)
 {
        int r;
@@ -487,15 +646,44 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
        if (!(lv = lv_from_lvid(cmd, lvid_s, 0)))
                return 0;
 
-       if (!lv_is_origin(lv))
-               origin_only = 0;
-
-       r = lv_info(cmd, lv, origin_only, info, with_open_count, with_read_ahead);
-       free_vg(lv->vg);
+       r = lv_info(cmd, lv, use_layer, info, with_open_count, with_read_ahead);
+       release_vg(lv->vg);
 
        return r;
 }
 
+int lv_check_not_in_use(struct cmd_context *cmd __attribute__((unused)),
+                       struct logical_volume *lv, struct lvinfo *info)
+{
+       if (!info->exists)
+               return 1;
+
+       /* If sysfs is not used, use open_count information only. */
+       if (!*dm_sysfs_dir()) {
+               if (info->open_count) {
+                       log_error("Logical volume %s/%s in use.",
+                                 lv->vg->name, lv->name);
+                       return 0;
+               }
+
+               return 1;
+       }
+
+       if (dm_device_has_holders(info->major, info->minor)) {
+               log_error("Logical volume %s/%s is used by another device.",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       if (dm_device_has_mounted_fs(info->major, info->minor)) {
+               log_error("Logical volume %s/%s contains a filesystem in use.",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       return 1;
+}
+
 /*
  * Returns 1 if percent set, else 0 on failure.
  */
@@ -507,7 +695,9 @@ int lv_check_transient(struct logical_volume *lv)
        if (!activation())
                return 0;
 
-       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name)))
+       log_debug("Checking transient status for LV %s/%s", lv->vg->name, lv->name);
+
+       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
                return_0;
 
        if (!(r = dev_manager_transient(dm, lv)))
@@ -529,7 +719,9 @@ int lv_snapshot_percent(const struct logical_volume *lv, percent_t *percent)
        if (!activation())
                return 0;
 
-       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name)))
+       log_debug("Checking snapshot percent for LV %s/%s", lv->vg->name, lv->name);
+
+       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
                return_0;
 
        if (!(r = dev_manager_snapshot_percent(dm, lv, percent)))
@@ -541,7 +733,7 @@ int lv_snapshot_percent(const struct logical_volume *lv, percent_t *percent)
 }
 
 /* FIXME Merge with snapshot_percent */
-int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
+int lv_mirror_percent(struct cmd_context *cmd, const struct logical_volume *lv,
                      int wait, percent_t *percent, uint32_t *event_nr)
 {
        int r;
@@ -558,13 +750,15 @@ int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
        if (!activation())
                return 0;
 
+       log_debug("Checking mirror percent for LV %s/%s", lv->vg->name, lv->name);
+
        if (!lv_info(cmd, lv, 0, &info, 0, 0))
                return_0;
 
        if (!info.exists)
                return 0;
 
-       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name)))
+       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
                return_0;
 
        if (!(r = dev_manager_mirror_percent(dm, lv, wait, percent, event_nr)))
@@ -575,7 +769,94 @@ int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
        return r;
 }
 
-static int _lv_active(struct cmd_context *cmd, struct logical_volume *lv)
+int lv_raid_percent(const struct logical_volume *lv, percent_t *percent)
+{
+       return lv_mirror_percent(lv->vg->cmd, lv, 0, percent, NULL);
+}
+
+/*
+ * Returns data or metadata percent usage, depends on metadata 0/1.
+ * Returns 1 if percent set, else 0 on failure.
+ */
+int lv_thin_pool_percent(const struct logical_volume *lv, int metadata,
+                        percent_t *percent)
+{
+       int r;
+       struct dev_manager *dm;
+
+       if (!activation())
+               return 0;
+
+       log_debug("Checking thin %sdata percent for LV %s/%s",
+                 (metadata) ? "meta" : "", lv->vg->name, lv->name);
+
+       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
+               return_0;
+
+       if (!(r = dev_manager_thin_pool_percent(dm, lv, metadata, percent)))
+               stack;
+
+       dev_manager_destroy(dm);
+
+       return r;
+}
+
+/*
+ * Returns 1 if percent set, else 0 on failure.
+ */
+int lv_thin_percent(const struct logical_volume *lv,
+                   int mapped, percent_t *percent)
+{
+       int r;
+       struct dev_manager *dm;
+
+       if (!activation())
+               return 0;
+
+       log_debug("Checking thin percent for LV %s/%s",
+                 lv->vg->name, lv->name);
+
+       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
+               return_0;
+
+       if (!(r = dev_manager_thin_percent(dm, lv, mapped, percent)))
+               stack;
+
+       dev_manager_destroy(dm);
+
+       return r;
+}
+
+/*
+ * Returns 1 if transaction_id set, else 0 on failure.
+ */
+int lv_thin_pool_transaction_id(const struct logical_volume *lv,
+                               uint64_t *transaction_id)
+{
+       int r;
+       struct dev_manager *dm;
+       struct dm_status_thin_pool *status;
+
+       if (!activation())
+               return 0;
+
+       log_debug("Checking thin percent for LV %s/%s",
+                 lv->vg->name, lv->name);
+
+       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
+               return_0;
+
+       if (!(r = dev_manager_thin_pool_status(dm, lv, &status)))
+               stack;
+       else
+               *transaction_id = status->transaction_id;
+
+       dev_manager_destroy(dm);
+
+       return r;
+}
+
+static int _lv_active(struct cmd_context *cmd, const struct logical_volume *lv)
 {
        struct lvinfo info;
 
@@ -599,33 +880,40 @@ static int _lv_open_count(struct cmd_context *cmd, struct logical_volume *lv)
        return info.open_count;
 }
 
-static int _lv_activate_lv(struct logical_volume *lv, unsigned origin_only)
+static int _lv_activate_lv(struct logical_volume *lv, struct lv_activate_opts *laopts)
 {
        int r;
        struct dev_manager *dm;
 
-       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name)))
+       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, (lv->status & PVMOVE) ? 0 : 1)))
                return_0;
 
-       if (!(r = dev_manager_activate(dm, lv, origin_only)))
+       if (!(r = dev_manager_activate(dm, lv, laopts)))
                stack;
 
        dev_manager_destroy(dm);
        return r;
 }
 
-static int _lv_preload(struct logical_volume *lv, unsigned origin_only, int *flush_required)
+static int _lv_preload(struct logical_volume *lv, struct lv_activate_opts *laopts,
+                      int *flush_required)
 {
-       int r;
+       int r = 0;
        struct dev_manager *dm;
+       int old_readonly = laopts->read_only;
 
-       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name)))
-               return_0;
+       laopts->read_only = _passes_readonly_filter(lv->vg->cmd, lv);
 
-       if (!(r = dev_manager_preload(dm, lv, origin_only, flush_required)))
+       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, (lv->status & PVMOVE) ? 0 : 1)))
+               goto_out;
+
+       if (!(r = dev_manager_preload(dm, lv, laopts, flush_required)))
                stack;
 
        dev_manager_destroy(dm);
+
+       laopts->read_only = old_readonly;
+out:
        return r;
 }
 
@@ -634,7 +922,7 @@ static int _lv_deactivate(struct logical_volume *lv)
        int r;
        struct dev_manager *dm;
 
-       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name)))
+       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
                return_0;
 
        if (!(r = dev_manager_deactivate(dm, lv)))
@@ -644,15 +932,22 @@ static int _lv_deactivate(struct logical_volume *lv)
        return r;
 }
 
-static int _lv_suspend_lv(struct logical_volume *lv, unsigned origin_only, int lockfs, int flush_required)
+static int _lv_suspend_lv(struct logical_volume *lv, struct lv_activate_opts *laopts,
+                         int lockfs, int flush_required)
 {
        int r;
        struct dev_manager *dm;
 
-       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name)))
+       laopts->read_only = _passes_readonly_filter(lv->vg->cmd, lv);
+
+       /*
+        * When we are asked to manipulate (normally suspend/resume) the PVMOVE
+        * device directly, we don't want to touch the devices that use it.
+        */
+       if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, (lv->status & PVMOVE) ? 0 : 1)))
                return_0;
 
-       if (!(r = dev_manager_suspend(dm, lv, origin_only, lockfs, flush_required)))
+       if (!(r = dev_manager_suspend(dm, lv, laopts, lockfs, flush_required)))
                stack;
 
        dev_manager_destroy(dm);
@@ -661,9 +956,9 @@ static int _lv_suspend_lv(struct logical_volume *lv, unsigned origin_only, int l
 
 /*
  * These two functions return the number of visible LVs in the state,
- * or -1 on error.
+ * or -1 on error.  FIXME Check this.
  */
-int lvs_in_vg_activated(struct volume_group *vg)
+int lvs_in_vg_activated(const struct volume_group *vg)
 {
        struct lv_list *lvl;
        int count = 0;
@@ -671,10 +966,11 @@ int lvs_in_vg_activated(struct volume_group *vg)
        if (!activation())
                return 0;
 
-       dm_list_iterate_items(lvl, &vg->lvs) {
+       dm_list_iterate_items(lvl, &vg->lvs)
                if (lv_is_visible(lvl->lv))
                        count += (_lv_active(vg->cmd, lvl->lv) == 1);
-       }
+
+       log_debug("Counted %d active LVs in VG %s", count, vg->name);
 
        return count;
 }
@@ -687,48 +983,122 @@ int lvs_in_vg_opened(const struct volume_group *vg)
        if (!activation())
                return 0;
 
-       dm_list_iterate_items(lvl, &vg->lvs) {
+       dm_list_iterate_items(lvl, &vg->lvs)
                if (lv_is_visible(lvl->lv))
                        count += (_lv_open_count(vg->cmd, lvl->lv) > 0);
-       }
+
+       log_debug("Counted %d open LVs in VG %s", count, vg->name);
 
        return count;
 }
 
 /*
+ * _lv_is_active
+ * @lv:        logical volume being queried
+ * @locally:   set if active locally (when provided)
+ * @exclusive: set if active exclusively (when provided)
+ *
  * Determine whether an LV is active locally or in a cluster.
- * Assumes vg lock held.
- * Returns:
- * 0 - not active locally or on any node in cluster
- * 1 - active either locally or some node in the cluster
+ * In addition to the return code which indicates whether or
+ * not the LV is active somewhere, two other values are set
+ * to yield more information about the status of the activation:
+ *     return  locally exclusively     status
+ *     ======  ======= ===========     ======
+ *        0       0        0           not active
+ *        1       0        0           active remotely
+ *        1       0        1           exclusive remotely
+ *        1       1        0           active locally and possibly remotely
+ *        1       1        1           exclusive locally (or local && !cluster)
+ * The VG lock must be held to call this function.
+ *
+ * Returns: 0 or 1
  */
-int lv_is_active(struct logical_volume *lv)
+static int _lv_is_active(const struct logical_volume *lv,
+                        int *locally, int *exclusive)
 {
-       int ret;
+       int r, l, e; /* remote, local, and exclusive */
+
+       r = l = e = 0;
 
        if (_lv_active(lv->vg->cmd, lv))
-               return 1;
+               l = 1;
 
-       if (!vg_is_clustered(lv->vg))
-               return 0;
+       if (!vg_is_clustered(lv->vg)) {
+               if (l)
+                       e = 1;  /* exclusive by definition */
+               goto out;
+       }
 
-       if ((ret = remote_lock_held(lv->lvid.s)) >= 0)
-               return ret;
+       /* Active locally, and the caller doesn't care about exclusive */
+       if (l && !exclusive)
+               goto out;
+
+       if ((r = remote_lock_held(lv->lvid.s, &e)) >= 0)
+               goto out;
 
        /*
-        * Old compatibility code if locking doesn't support lock query
-        * FIXME: check status to not deactivate already activate device
+        * If lock query is not supported (due to interfacing with old
+        * code), then we cannot evaluate exclusivity properly.
+        *
+        * Old users of this function will never be affected by this,
+        * since they are only concerned about active vs. not active.
+        * New users of this function who specifically ask for 'exclusive'
+        * will be given an error message.
         */
-       if (activate_lv_excl(lv->vg->cmd, lv)) {
-               if (!deactivate_lv(lv->vg->cmd, lv))
-                       stack;
-               return 0;
-       }
+       log_error("Unable to determine exclusivity of %s", lv->name);
+
+       e = 0;
 
        /*
-        * Exclusive local activation failed so assume it is active elsewhere.
+        * We used to attempt activate_lv_excl_local(lv->vg->cmd, lv) here,
+        * but it's unreliable.
         */
-       return 1;
+
+out:
+       if (locally)
+               *locally = l;
+       if (exclusive)
+               *exclusive = e;
+
+       log_very_verbose("%s/%s is %sactive%s%s",
+                        lv->vg->name, lv->name,
+                        (r || l) ? "" : "not ",
+                        (exclusive && e) ? " exclusive" : "",
+                        e ? (l ? " locally" : " remotely") : "");
+
+       return r || l;
+}
+
+int lv_is_active(const struct logical_volume *lv)
+{
+       return _lv_is_active(lv, NULL, NULL);
+}
+
+int lv_is_active_but_not_locally(const struct logical_volume *lv)
+{
+       int l;
+       return _lv_is_active(lv, &l, NULL) && !l;
+}
+
+int lv_is_active_exclusive(const struct logical_volume *lv)
+{
+       int e;
+
+       return _lv_is_active(lv, NULL, &e) && e;
+}
+
+int lv_is_active_exclusive_locally(const struct logical_volume *lv)
+{
+       int l, e;
+
+       return _lv_is_active(lv, &l, &e) && l && e;
+}
+
+int lv_is_active_exclusive_remotely(const struct logical_volume *lv)
+{
+       int l, e;
+
+       return _lv_is_active(lv, &l, &e) && !l && e;
 }
 
 #ifdef DMEVENTD
@@ -773,20 +1143,32 @@ char *get_monitor_dso_path(struct cmd_context *cmd, const char *libpath)
        return path;
 }
 
+static char *_build_target_uuid(struct cmd_context *cmd, struct logical_volume *lv)
+{
+       const char *layer;
+
+       if (lv_is_thin_pool(lv))
+               layer = "tpool"; /* Monitor "tpool" for the "thin pool". */
+       else if (lv_is_origin(lv))
+               layer = "real"; /* Monitor "real" for "snapshot-origin". */
+       else
+               layer = NULL;
+
+       return build_dm_uuid(cmd->mem, lv->lvid.s, layer);
+}
+
 int target_registered_with_dmeventd(struct cmd_context *cmd, const char *dso,
                                    struct logical_volume *lv, int *pending)
 {
        char *uuid;
        enum dm_event_mask evmask = 0;
        struct dm_event_handler *dmevh;
-
        *pending = 0;
 
        if (!dso)
                return_0;
 
-       /* We always monitor the "real" device, never the "snapshot-origin" itself. */
-       if (!(uuid = build_dm_uuid(cmd->mem, lv->lvid.s, lv_is_origin(lv) ? "real" : NULL)))
+       if (!(uuid = _build_target_uuid(cmd, lv)))
                return_0;
 
        if (!(dmevh = _create_dm_event_handler(cmd, uuid, dso, 0, DM_EVENT_ALL_ERRORS)))
@@ -819,7 +1201,7 @@ int target_register_events(struct cmd_context *cmd, const char *dso, struct logi
                return_0;
 
        /* We always monitor the "real" device, never the "snapshot-origin" itself. */
-       if (!(uuid = build_dm_uuid(cmd->mem, lv->lvid.s, lv_is_origin(lv) ? "real" : NULL)))
+       if (!(uuid = _build_target_uuid(cmd, lv)))
                return_0;
 
        if (!(dmevh = _create_dm_event_handler(cmd, uuid, dso, timeout,
@@ -845,7 +1227,7 @@ int target_register_events(struct cmd_context *cmd, const char *dso, struct logi
  * Returns 1 otherwise.
  */
 int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv,
-                          unsigned origin_only, int monitor)
+                          const struct lv_activate_opts *laopts, int monitor)
 {
 #ifdef DMEVENTD
        int i, pending = 0, monitored;
@@ -855,6 +1237,12 @@ int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv,
        struct lv_segment *log_seg;
        int (*monitor_fn) (struct lv_segment *s, int e);
        uint32_t s;
+       static const struct lv_activate_opts zlaopts = { 0 };
+       static const struct lv_activate_opts thinopts = { .skip_in_use = 1 };
+       struct lvinfo info;
+
+       if (!laopts)
+               laopts = &zlaopts;
 
        /* skip dmeventd code altogether */
        if (dmeventd_monitor_mode() == DMEVENTD_MONITOR_IGNORE)
@@ -866,22 +1254,35 @@ int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv,
        if (monitor && !dmeventd_monitor_mode())
                return 1;
 
+       /*
+        * Allow to unmonitor thin pool via explicit pool unmonitor
+        * or unmonitor before the last thin pool user deactivation
+        * Skip unmonitor, if invoked via unmonitor of thin volume
+        * and there is another thin pool user (open_count > 1)
+        */
+       if (laopts->skip_in_use && lv_info(lv->vg->cmd, lv, 1, &info, 1, 0) &&
+           (info.open_count != 1)) {
+               log_debug("Skipping unmonitor of opened %s (open:%d)",
+                         lv->name, info.open_count);
+               return 1;
+       }
+
        /*
         * In case of a snapshot device, we monitor lv->snapshot->lv,
         * not the actual LV itself.
         */
-       if (lv_is_cow(lv) && !lv_is_merging_cow(lv))
-               return monitor_dev_for_events(cmd, lv->snapshot->lv, 0, monitor);
+       if (lv_is_cow(lv) && (laopts->no_merging || !lv_is_merging_cow(lv)))
+               return monitor_dev_for_events(cmd, lv->snapshot->lv, NULL, monitor);
 
        /*
         * In case this LV is a snapshot origin, we instead monitor
         * each of its respective snapshots.  The origin itself may
         * also need to be monitored if it is a mirror, for example.
         */
-       if (!origin_only && lv_is_origin(lv))
+       if (!laopts->origin_only && lv_is_origin(lv))
                dm_list_iterate_safe(snh, snht, &lv->snapshot_segs)
                        if (!monitor_dev_for_events(cmd, dm_list_struct_base(snh,
-                                   struct lv_segment, origin_list)->cow, 0, monitor))
+                                   struct lv_segment, origin_list)->cow, NULL, monitor))
                                r = 0;
 
        /*
@@ -891,7 +1292,7 @@ int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv,
        if ((seg = first_seg(lv)) != NULL && seg->log_lv != NULL &&
            (log_seg = first_seg(seg->log_lv)) != NULL &&
            seg_is_mirrored(log_seg))
-               if (!monitor_dev_for_events(cmd, seg->log_lv, 0, monitor))
+               if (!monitor_dev_for_events(cmd, seg->log_lv, NULL, monitor))
                        r = 0;
 
        dm_list_iterate(tmp, &lv->segments) {
@@ -901,7 +1302,7 @@ int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv,
                for (s = 0; s < seg->area_count; s++) {
                        if (seg_type(seg, s) != AREA_LV)
                                continue;
-                       if (!monitor_dev_for_events(cmd, seg_lv(seg, s), 0,
+                       if (!monitor_dev_for_events(cmd, seg_lv(seg, s), NULL,
                                                    monitor)) {
                                log_error("Failed to %smonitor %s",
                                          monitor ? "" : "un",
@@ -910,6 +1311,21 @@ int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv,
                        }
                }
 
+               /*
+                * If requested unmonitoring of thin volume, request test
+                * if there is no other thin pool user
+                *
+                * FIXME: code here looks like _lv_postorder()
+                */
+               if (seg->pool_lv &&
+                   !monitor_dev_for_events(cmd, seg->pool_lv,
+                                           (!monitor) ? &thinopts : NULL, monitor))
+                       r = 0;
+
+               if (seg->metadata_lv &&
+                   !monitor_dev_for_events(cmd, seg->metadata_lv, NULL, monitor))
+                       r = 0;
+
                if (!seg_monitored(seg) || (seg->status & PVMOVE))
                        continue;
 
@@ -975,18 +1391,45 @@ int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv,
                        r = (monitored && monitor) || (!monitored && !monitor);
        }
 
+       if (!r && !error_message_produced())
+               log_error("%sonitoring %s/%s failed.", monitor ? "M" : "Not m",
+                         lv->vg->name, lv->name);
        return r;
 #else
        return 1;
 #endif
 }
 
+struct detached_lv_data {
+       struct logical_volume *lv_pre;
+       struct lv_activate_opts *laopts;
+       int *flush_required;
+};
+
+static int _preload_detached_lv(struct cmd_context *cmd, struct logical_volume *lv, void *data)
+{
+       struct detached_lv_data *detached = data;
+       struct lv_list *lvl_pre;
+
+       if ((lvl_pre = find_lv_in_vg(detached->lv_pre->vg, lv->name))) {
+               if (lv_is_visible(lvl_pre->lv) && lv_is_active(lv) && (!lv_is_cow(lv) || !lv_is_cow(lvl_pre->lv)) &&
+                   !_lv_preload(lvl_pre->lv, detached->laopts, detached->flush_required))
+                       return_0;
+       }
+
+       return 1;
+}
+
 static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
-                      unsigned origin_only, int error_if_not_suspended)
+                      struct lv_activate_opts *laopts, int error_if_not_suspended)
 {
-       struct logical_volume *lv = NULL, *lv_pre = NULL;
+       struct logical_volume *lv = NULL, *lv_pre = NULL, *pvmove_lv = NULL;
+       struct lv_list *lvl_pre;
+       struct seg_list *sl;
+        struct lv_segment *snap_seg;
        struct lvinfo info;
        int r = 0, lockfs = 0, flush_required = 0;
+       struct detached_lv_data detached;
 
        if (!activation())
                return 1;
@@ -999,23 +1442,23 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
                goto_out;
 
        /* Ignore origin_only unless LV is origin in both old and new metadata */
-       if (!lv_is_origin(lv) || !lv_is_origin(lv_pre))
-               origin_only = 0;
+       if (!lv_is_thin_volume(lv) && !(lv_is_origin(lv) && lv_is_origin(lv_pre)))
+               laopts->origin_only = 0;
 
        if (test_mode()) {
-               _skip("Suspending %s%s.", lv->name, origin_only ? " origin without snapshots" : "");
+               _skip("Suspending %s%s.", lv->name, laopts->origin_only ? " origin without snapshots" : "");
                r = 1;
                goto out;
        }
 
-       if (!lv_info(cmd, lv, origin_only, &info, 0, 0))
+       if (!lv_info(cmd, lv, laopts->origin_only, &info, 0, 0))
                goto_out;
 
        if (!info.exists || info.suspended) {
                if (!error_if_not_suspended) {
                        r = 1;
                        if (info.suspended)
-                               memlock_inc(cmd);
+                               critical_section_inc(cmd, "already suspended");
                }
                goto out;
        }
@@ -1025,46 +1468,131 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
 
        lv_calculate_readahead(lv, NULL);
 
-       /* If VG was precommitted, preload devices for the LV */
-       if ((lv_pre->vg->status & PRECOMMITTED)) {
-               if (!_lv_preload(lv_pre, origin_only, &flush_required)) {
+       /*
+        * Preload devices for the LV.
+        * If the PVMOVE LV is being removed, it's only present in the old
+        * metadata and not the new, so we must explicitly add the new
+        * tables for all the changed LVs here, as the relationships
+        * are not found by walking the new metadata.
+        */
+       if (!(lv_pre->status & LOCKED) &&
+           (lv->status & LOCKED) &&
+           (pvmove_lv = find_pvmove_lv_in_lv(lv))) {
+               /* Preload all the LVs above the PVMOVE LV */
+               dm_list_iterate_items(sl, &pvmove_lv->segs_using_this_lv) {
+                       if (!(lvl_pre = find_lv_in_vg(lv_pre->vg, sl->seg->lv->name))) {
+                               log_error(INTERNAL_ERROR "LV %s missing from preload metadata", sl->seg->lv->name);
+                               goto out;
+                       }
+                       if (!_lv_preload(lvl_pre->lv, laopts, &flush_required))
+                               goto_out;
+               }
+               /* Now preload the PVMOVE LV itself */
+               if (!(lvl_pre = find_lv_in_vg(lv_pre->vg, pvmove_lv->name))) {
+                       log_error(INTERNAL_ERROR "LV %s missing from preload metadata", pvmove_lv->name);
+                       goto out;
+               }
+               if (!_lv_preload(lvl_pre->lv, laopts, &flush_required))
+                       goto_out;
+       } else {
+               if (!_lv_preload(lv_pre, laopts, &flush_required))
                        /* FIXME Revert preloading */
                        goto_out;
+
+               /*
+                * Search for existing LVs that have become detached and preload them.
+                */
+               detached.lv_pre = lv_pre;
+               detached.laopts = laopts;
+               detached.flush_required = &flush_required;
+
+               if (!for_each_sub_lv(cmd, lv, &_preload_detached_lv, &detached))
+                       goto_out;
+
+               /*
+                * Preload any snapshots that are being removed.
+                */
+               if (!laopts->origin_only && lv_is_origin(lv)) {
+                       dm_list_iterate_items_gen(snap_seg, &lv->snapshot_segs, origin_list) {
+                               if (!(lvl_pre = find_lv_in_vg_by_lvid(lv_pre->vg, &snap_seg->cow->lvid))) {
+                                       log_error(INTERNAL_ERROR "LV %s (%s) missing from preload metadata",
+                                                 snap_seg->cow->name, snap_seg->cow->lvid.id[1].uuid);
+                                       goto out;
+                               }
+                               if (!lv_is_cow(lvl_pre->lv) &&
+                                   !_lv_preload(lvl_pre->lv, laopts, &flush_required))
+                                       goto_out;
+                       }
                }
        }
 
-       if (!monitor_dev_for_events(cmd, lv, origin_only, 0))
+       if (!monitor_dev_for_events(cmd, lv, laopts, 0))
                /* FIXME Consider aborting here */
                stack;
 
-       memlock_inc(cmd);
+       critical_section_inc(cmd, "suspending");
+       if (pvmove_lv)
+               critical_section_inc(cmd, "suspending pvmove LV");
 
-       if (!origin_only &&
+       if (!laopts->origin_only &&
            (lv_is_origin(lv_pre) || lv_is_cow(lv_pre)))
                lockfs = 1;
 
-       if (!_lv_suspend_lv(lv, origin_only, lockfs, flush_required)) {
-               memlock_dec(cmd);
-               fs_unlock();
-               goto out;
+       if (laopts->origin_only && lv_is_thin_volume(lv) && lv_is_thin_volume(lv_pre))
+               lockfs = 1;
+
+       /*
+        * Suspending an LV directly above a PVMOVE LV also
+        * suspends other LVs using that same PVMOVE LV.
+        * FIXME Remove this and delay the 'clear node' until
+        * after the code knows whether there's a different
+        * inactive table to load or not instead so lv_suspend
+        * can be called separately for each LV safely.
+        */
+       if ((lv_pre->vg->status & PRECOMMITTED) &&
+           (lv_pre->status & LOCKED) && find_pvmove_lv_in_lv(lv_pre)) {
+               if (!_lv_suspend_lv(lv_pre, laopts, lockfs, flush_required)) {
+                       critical_section_dec(cmd, "failed precommitted suspend");
+                       if (pvmove_lv)
+                               critical_section_dec(cmd, "failed precommitted suspend (pvmove)");
+                       goto_out;
+               }
+       } else {
+               /* Normal suspend */
+               if (!_lv_suspend_lv(lv, laopts, lockfs, flush_required)) {
+                       critical_section_dec(cmd, "failed suspend");
+                       if (pvmove_lv)
+                               critical_section_dec(cmd, "failed suspend (pvmove)");
+                       goto_out;
+               }
        }
 
        r = 1;
 out:
        if (lv_pre)
-               free_vg(lv_pre->vg);
+               release_vg(lv_pre->vg);
        if (lv) {
                lv_release_replicator_vgs(lv);
-               free_vg(lv->vg);
+               release_vg(lv->vg);
        }
 
        return r;
 }
 
-/* Returns success if the device is not active */
-int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only)
+/*
+ * In a cluster, set exclusive to indicate that only one node is using the
+ * device.  Any preloaded tables may then use non-clustered targets.
+ *
+ * Returns success if the device is not active
+ */
+int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, unsigned exclusive)
 {
-       return _lv_suspend(cmd, lvid_s, origin_only, 0);
+       struct lv_activate_opts laopts = {
+               .origin_only = origin_only,
+               .exclusive = exclusive
+       };
+
+       return _lv_suspend(cmd, lvid_s, &laopts, 0);
 }
 
 /* No longer used */
@@ -1076,12 +1604,12 @@ int lv_suspend(struct cmd_context *cmd, const char *lvid_s)
 ***********/
 
 static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
-                     unsigned origin_only,
-                     int error_if_not_active)
+                     struct lv_activate_opts *laopts, int error_if_not_active)
 {
        struct logical_volume *lv;
        struct lvinfo info;
        int r = 0;
+       int messages_only = 0;
 
        if (!activation())
                return 1;
@@ -1089,51 +1617,82 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
        if (!(lv = lv_from_lvid(cmd, lvid_s, 0)))
                goto_out;
 
-       if (!lv_is_origin(lv))
-               origin_only = 0;
+       if (lv_is_thin_pool(lv) && laopts->origin_only)
+               messages_only = 1;
+
+       if (!lv_is_origin(lv) && !lv_is_thin_volume(lv))
+               laopts->origin_only = 0;
 
        if (test_mode()) {
-               _skip("Resuming %s%s.", lv->name, origin_only ? " without snapshots" : "");
+               _skip("Resuming %s%s%s.", lv->name, laopts->origin_only ? " without snapshots" : "",
+                     laopts->revert ? " (reverting)" : "");
                r = 1;
                goto out;
        }
 
-       if (!lv_info(cmd, lv, origin_only, &info, 0, 0))
+       log_debug("Resuming LV %s/%s%s%s%s.", lv->vg->name, lv->name,
+                 error_if_not_active ? "" : " if active",
+                 laopts->origin_only ? " without snapshots" : "",
+                 laopts->revert ? " (reverting)" : "");
+
+       if (!lv_info(cmd, lv, laopts->origin_only, &info, 0, 0))
                goto_out;
 
-       if (!info.exists || !info.suspended) {
+       if (!info.exists || !(info.suspended || messages_only)) {
                if (error_if_not_active)
                        goto_out;
                r = 1;
+               if (!info.suspended)
+                       critical_section_dec(cmd, "already resumed");
                goto out;
        }
 
-       if (!_lv_activate_lv(lv, origin_only))
+       laopts->read_only = _passes_readonly_filter(cmd, lv);
+
+       if (!_lv_activate_lv(lv, laopts))
                goto_out;
 
-       memlock_dec(cmd);
-       fs_unlock();
+       critical_section_dec(cmd, "resumed");
 
-       if (!monitor_dev_for_events(cmd, lv, origin_only, 1))
+       if (!monitor_dev_for_events(cmd, lv, laopts, 1))
                stack;
 
        r = 1;
 out:
        if (lv)
-               free_vg(lv->vg);
+               release_vg(lv->vg);
 
        return r;
 }
 
-/* Returns success if the device is not active */
-int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only)
+/*
+ * In a cluster, set exclusive to indicate that only one node is using the
+ * device.  Any tables loaded may then use non-clustered targets.
+ *
+ * @origin_only
+ * @exclusive   This parameter only has an affect in cluster-context.
+ *              It forces local target type to be used (instead of
+ *              cluster-aware type).
+ * Returns success if the device is not active
+ */
+int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s,
+                       unsigned origin_only, unsigned exclusive,
+                       unsigned revert)
 {
-       return _lv_resume(cmd, lvid_s, origin_only, 0);
+       struct lv_activate_opts laopts = {
+               .origin_only = origin_only,
+               .exclusive = exclusive,
+               .revert = revert
+       };
+
+       return _lv_resume(cmd, lvid_s, &laopts, 0);
 }
 
 int lv_resume(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only)
 {
-       return _lv_resume(cmd, lvid_s, origin_only, 1);
+       struct lv_activate_opts laopts = { .origin_only = origin_only, };
+
+       return _lv_resume(cmd, lvid_s, &laopts, 1);
 }
 
 static int _lv_has_open_snapshots(struct logical_volume *lv)
@@ -1177,6 +1736,8 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
                goto out;
        }
 
+       log_debug("Deactivating %s/%s.", lv->vg->name, lv->name);
+
        if (!lv_info(cmd, lv, 0, &info, 1, 0))
                goto_out;
 
@@ -1186,11 +1747,9 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
        }
 
        if (lv_is_visible(lv)) {
-               if (info.open_count) {
-                       log_error("LV %s/%s in use: not deactivating",
-                                 lv->vg->name, lv->name);
-                       goto out;
-               }
+               if (!lv_check_not_in_use(cmd, lv, &info))
+                       goto_out;
+
                if (lv_is_origin(lv) && _lv_has_open_snapshots(lv))
                        goto_out;
        }
@@ -1200,20 +1759,19 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
 
        lv_calculate_readahead(lv, NULL);
 
-       if (!monitor_dev_for_events(cmd, lv, 0, 0))
+       if (!monitor_dev_for_events(cmd, lv, NULL, 0))
                stack;
 
-       memlock_inc(cmd);
+       critical_section_inc(cmd, "deactivating");
        r = _lv_deactivate(lv);
-       memlock_dec(cmd);
-       fs_unlock();
+       critical_section_dec(cmd, "deactivated");
 
-       if (!lv_info(cmd, lv, 0, &info, 1, 0) || info.exists)
+       if (!lv_info(cmd, lv, 0, &info, 0, 0) || info.exists)
                r = 0;
 out:
        if (lv) {
                lv_release_replicator_vgs(lv);
-               free_vg(lv->vg);
+               release_vg(lv->vg);
        }
 
        return r;
@@ -1243,13 +1801,13 @@ int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
        r = 1;
 out:
        if (lv)
-               free_vg(lv->vg);
+               release_vg(lv->vg);
 
        return r;
 }
 
 static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
-                       int exclusive, int filter)
+                       struct lv_activate_opts *laopts, int filter)
 {
        struct logical_volume *lv;
        struct lvinfo info;
@@ -1285,10 +1843,21 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
                goto out;
        }
 
+       if (filter)
+               laopts->read_only = _passes_readonly_filter(cmd, lv);
+
+       log_debug("Activating %s/%s%s%s.", lv->vg->name, lv->name,
+                 laopts->exclusive ? " exclusively" : "",
+                 laopts->read_only ? " read-only" : "");
+
        if (!lv_info(cmd, lv, 0, &info, 0, 0))
                goto_out;
 
-       if (info.exists && !info.suspended && info.live_table) {
+       /*
+        * Nothing to do?
+        */
+       if (info.exists && !info.suspended && info.live_table &&
+           (info.read_only == read_only_lv(lv, laopts))) {
                r = 1;
                goto out;
        }
@@ -1298,22 +1867,18 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
 
        lv_calculate_readahead(lv, NULL);
 
-       if (exclusive)
-               lv->status |= ACTIVATE_EXCL;
-
-       memlock_inc(cmd);
-       if (!(r = _lv_activate_lv(lv, 0)))
+       critical_section_inc(cmd, "activating");
+       if (!(r = _lv_activate_lv(lv, laopts)))
                stack;
-       memlock_dec(cmd);
-       fs_unlock();
+       critical_section_dec(cmd, "activated");
 
-       if (r && !monitor_dev_for_events(cmd, lv, 0, 1))
+       if (r && !monitor_dev_for_events(cmd, lv, laopts, 1))
                stack;
 
 out:
        if (lv) {
                lv_release_replicator_vgs(lv);
-               free_vg(lv->vg);
+               release_vg(lv->vg);
        }
 
        return r;
@@ -1322,7 +1887,9 @@ out:
 /* Activate LV */
 int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive)
 {
-       if (!_lv_activate(cmd, lvid_s, exclusive, 0))
+       struct lv_activate_opts laopts = { .exclusive = exclusive };
+
+       if (!_lv_activate(cmd, lvid_s, &laopts, 0))
                return_0;
 
        return 1;
@@ -1331,7 +1898,9 @@ int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive)
 /* Activate LV only if it passes filter */
 int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive)
 {
-       if (!_lv_activate(cmd, lvid_s, exclusive, 1))
+       struct lv_activate_opts laopts = { .exclusive = exclusive };
+
+       if (!_lv_activate(cmd, lvid_s, &laopts, 1))
                return_0;
 
        return 1;
@@ -1364,7 +1933,7 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
 int pv_uses_vg(struct physical_volume *pv,
               struct volume_group *vg)
 {
-       if (!activation())
+       if (!activation() || !pv->dev)
                return 0;
 
        if (!dm_is_dm_major(MAJOR(pv->dev->dev)))
index df46ac2e19491020ff19de8ba4534d2e5f70cf11..ba24d2a58481baff52832abe50b6261d995543d1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.  
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -30,9 +30,29 @@ struct lvinfo {
        uint32_t read_ahead;
 };
 
+struct lv_activate_opts {
+       int exclusive;
+       int origin_only;
+       int no_merging;
+       int real_pool;
+       int is_activate;
+       int skip_in_use;
+       unsigned revert;
+       unsigned read_only;
+};
+
 /* target attribute flags */
 #define MIRROR_LOG_CLUSTERED   0x00000001U
 
+/* thin target attribute flags */
+enum {
+       /* bitfields - new features from 1.1 version */
+       THIN_FEATURE_DISCARDS                   = (1 << 0),
+       THIN_FEATURE_EXTERNAL_ORIGIN            = (1 << 1),
+       THIN_FEATURE_HELD_ROOT                  = (1 << 2),
+       THIN_FEATURE_BLOCK_SIZE                 = (1 << 3),
+};
+
 void set_activation(int activation);
 int activation(void);
 
@@ -45,6 +65,7 @@ int target_present(struct cmd_context *cmd, const char *target_name,
                   int use_modprobe);
 int target_version(const char *target_name, uint32_t *maj,
                   uint32_t *min, uint32_t *patchlevel);
+int lvm_dm_prefix_check(int major, int minor, const char *prefix);
 int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
                         struct dm_list *modules);
 int list_lv_modules(struct dm_pool *mem, const struct logical_volume *lv,
@@ -54,9 +75,10 @@ void activation_release(void);
 void activation_exit(void);
 
 /* int lv_suspend(struct cmd_context *cmd, const char *lvid_s); */
-int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only);
+int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, unsigned exclusive);
 int lv_resume(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only);
-int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only);
+int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s,
+                       unsigned origin_only, unsigned exclusive, unsigned revert);
 int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive);
 int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s,
                            int exclusive);
@@ -67,39 +89,57 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv);
 /*
  * Returns 1 if info structure has been populated, else 0.
  */
-int lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
-           unsigned origin_only, struct lvinfo *info,
-           int with_open_count, int with_read_ahead);
-int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only,
+int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int use_layer,
+           struct lvinfo *info, int with_open_count, int with_read_ahead);
+int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
                    struct lvinfo *info, int with_open_count, int with_read_ahead);
 
+int lv_check_not_in_use(struct cmd_context *cmd, struct logical_volume *lv,
+                       struct lvinfo *info);
+
 /*
  * Returns 1 if activate_lv has been set: 1 = activate; 0 = don't.
  */
 int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
                         int *activate_lv);
+/*
+ * Checks against the auto_activation_volume_list and
+ * returns 1 if the LV should be activated, 0 otherwise.
+ */
+int lv_passes_auto_activation_filter(struct cmd_context *cmd, struct logical_volume *lv);
 
 int lv_check_transient(struct logical_volume *lv);
 /*
  * Returns 1 if percent has been set, else 0.
  */
 int lv_snapshot_percent(const struct logical_volume *lv, percent_t *percent);
-int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
+int lv_mirror_percent(struct cmd_context *cmd, const struct logical_volume *lv,
                      int wait, percent_t *percent, uint32_t *event_nr);
+int lv_raid_percent(const struct logical_volume *lv, percent_t *percent);
+int lv_thin_pool_percent(const struct logical_volume *lv, int metadata,
+                        percent_t *percent);
+int lv_thin_percent(const struct logical_volume *lv, int mapped,
+                   percent_t *percent);
+int lv_thin_pool_transaction_id(const struct logical_volume *lv,
+                               uint64_t *transaction_id);
 
 /*
  * Return number of LVs in the VG that are active.
  */
-int lvs_in_vg_activated(struct volume_group *vg);
+int lvs_in_vg_activated(const struct volume_group *vg);
 int lvs_in_vg_opened(const struct volume_group *vg);
 
-int lv_is_active(struct logical_volume *lv);
+int lv_is_active(const struct logical_volume *lv);
+int lv_is_active_but_not_locally(const struct logical_volume *lv);
+int lv_is_active_exclusive(const struct logical_volume *lv);
+int lv_is_active_exclusive_locally(const struct logical_volume *lv);
+int lv_is_active_exclusive_remotely(const struct logical_volume *lv);
 
 int lv_has_target_type(struct dm_pool *mem, struct logical_volume *lv,
                       const char *layer, const char *target_type);
 
 int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv,
-                          unsigned origin_only, int do_reg);
+                          const struct lv_activate_opts *laopts, int do_reg);
 
 #ifdef DMEVENTD
 #  include "libdevmapper-event.h"
@@ -110,6 +150,10 @@ int target_register_events(struct cmd_context *cmd, const char *dso, struct logi
                            int evmask __attribute__((unused)), int set, int timeout);
 #endif
 
+int add_linear_area_to_dtree(struct dm_tree_node *node, uint64_t size,
+                            uint32_t extent_size, int use_linear_target,
+                            const char *vgname, const char *lvname);
+
 /*
  * Returns 1 if PV has a dependency tree that uses anything in VG.
  */
@@ -121,4 +165,9 @@ int pv_uses_vg(struct physical_volume *pv,
  */
 int device_is_usable(struct device *dev);
 
+/*
+ * Declaration moved here from fs.h to keep header fs.h hidden
+ */
+void fs_unlock(void);
+
 #endif
index a11d918fe775a2d4d9c8e35ff6522fafda354491..31c1c27138a99775dab81a1a2565731ae6a3e58c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -14,7 +14,6 @@
  */
 
 #include "lib.h"
-#include "str_list.h"
 #include "dev_manager.h"
 #include "lvm-string.h"
 #include "fs.h"
@@ -26,6 +25,7 @@
 #include "config.h"
 #include "filter.h"
 #include "activate.h"
+#include "lvm-exec.h"
 
 #include <limits.h>
 #include <dirent.h>
@@ -49,6 +49,7 @@ struct dev_manager {
        void *target_state;
        uint32_t pvmove_mirror_count;
        int flush_required;
+       unsigned track_pvmove_deps;
 
        char *vg_name;
 };
@@ -58,9 +59,11 @@ struct lv_layer {
        const char *old_name;
 };
 
-static int _read_only_lv(struct logical_volume *lv)
+static const char _thin_layer[] = "tpool";
+
+int read_only_lv(struct logical_volume *lv, struct lv_activate_opts *laopts)
 {
-       return (!(lv->vg->status & LVM_WRITE) || !(lv->status & LVM_WRITE));
+       return (laopts->read_only || !(lv->vg->status & LVM_WRITE) || !(lv->status & LVM_WRITE));
 }
 
 /*
@@ -75,19 +78,25 @@ static struct dm_task *_setup_task(const char *name, const char *uuid,
        if (!(dmt = dm_task_create(task)))
                return_NULL;
 
-       if (name)
-               dm_task_set_name(dmt, name);
+       if (name && !dm_task_set_name(dmt, name))
+               goto_out;
 
-       if (uuid && *uuid)
-               dm_task_set_uuid(dmt, uuid);
+       if (uuid && *uuid && !dm_task_set_uuid(dmt, uuid))
+               goto_out;
 
-       if (event_nr)
-               dm_task_set_event_nr(dmt, *event_nr);
+       if (event_nr && !dm_task_set_event_nr(dmt, *event_nr))
+               goto_out;
 
-       if (major)
-               dm_task_set_major_minor(dmt, major, minor, 1);
+       if (major && !dm_task_set_major_minor(dmt, major, minor, 1))
+               goto_out;
 
+       if (activation_checks() && !dm_task_enable_checks(dmt))
+               goto_out;
+               
        return dmt;
+      out:
+       dm_task_destroy(dmt);
+       return NULL;
 }
 
 static int _info_run(const char *name, const char *dlid, struct dm_info *info,
@@ -138,14 +147,15 @@ int device_is_usable(struct device *dev)
        int only_error_target = 1;
        int r = 0;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) {
-               log_error("Failed to create dm_task struct to check dev status");
-               return 0;
-       }
+       if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
+               return_0;
 
        if (!dm_task_set_major_minor(dmt, MAJOR(dev->dev), MINOR(dev->dev), 1))
                goto_out;
 
+       if (activation_checks() && !dm_task_enable_checks(dmt))
+               goto_out;
+               
        if (!dm_task_run(dmt)) {
                log_error("Failed to get state of mapped device");
                goto out;
@@ -261,7 +271,7 @@ int dev_manager_info(struct dm_pool *mem, const struct logical_volume *lv,
        char *dlid, *name;
        int r;
 
-       if (!(name = build_dm_name(mem, lv->vg->name, lv->name, layer))) {
+       if (!(name = dm_build_dm_name(mem, lv->vg->name, lv->name, layer))) {
                log_error("name build failed for %s", lv->name);
                return 0;
        }
@@ -306,6 +316,7 @@ static const struct dm_info *_cached_info(struct dm_pool *mem,
        return dinfo;
 }
 
+#if 0
 /* FIXME Interface must cope with multiple targets */
 static int _status_run(const char *name, const char *uuid,
                       unsigned long long *s, unsigned long long *l,
@@ -383,6 +394,7 @@ static int _status(const char *name, const char *uuid,
 
        return 0;
 }
+#endif
 
 int lv_has_target_type(struct dm_pool *mem, struct logical_volume *lv,
                       const char *layer, const char *target_type)
@@ -401,7 +413,7 @@ int lv_has_target_type(struct dm_pool *mem, struct logical_volume *lv,
 
        if (!(dmt = _setup_task(NULL, dlid, 0,
                                DM_DEVICE_STATUS, 0, 0)))
-               return_0;
+               goto_bad;
 
        if (!dm_task_no_open_count(dmt))
                log_error("Failed to disable open_count");
@@ -423,14 +435,56 @@ int lv_has_target_type(struct dm_pool *mem, struct logical_volume *lv,
                }
        } while (next);
 
- out:
+out:
        dm_task_destroy(dmt);
+bad:
+       dm_pool_free(mem, dlid);
+
        return r;
 }
 
+int add_linear_area_to_dtree(struct dm_tree_node *node, uint64_t size, uint32_t extent_size, int use_linear_target, const char *vgname, const char *lvname)
+{
+       uint32_t page_size;
+
+       /*
+        * Use striped or linear target?
+        */
+       if (!use_linear_target) {
+               page_size = lvm_getpagesize() >> SECTOR_SHIFT;
+
+               /*
+                * We'll use the extent size as the stripe size.
+                * Extent size and page size are always powers of 2.
+                * The striped target requires that the stripe size is
+                * divisible by the page size.
+                */
+               if (extent_size >= page_size) {
+                       /* Use striped target */
+                       if (!dm_tree_node_add_striped_target(node, size, extent_size))
+                               return_0;
+                       return 1;
+               } else
+                       /* Some exotic cases are unsupported by striped. */
+                       log_warn("WARNING: Using linear target for %s/%s: Striped requires extent size (%" PRIu32 " sectors) >= page size (%" PRIu32 ").",
+                                vgname, lvname, extent_size, page_size);
+       }
+
+       /*
+        * Use linear target.
+        */
+       if (!dm_tree_node_add_linear_target(node, size))
+               return_0;
+
+       return 1;
+}
+
 static percent_range_t _combine_percent(percent_t a, percent_t b,
                                         uint32_t numerator, uint32_t denominator)
 {
+       if (a == PERCENT_MERGE_FAILED || b == PERCENT_MERGE_FAILED)
+               return PERCENT_MERGE_FAILED;
+
        if (a == PERCENT_INVALID || b == PERCENT_INVALID)
                return PERCENT_INVALID;
 
@@ -440,7 +494,7 @@ static percent_range_t _combine_percent(percent_t a, percent_t b,
        if (a == PERCENT_0 && b == PERCENT_0)
                return PERCENT_0;
 
-       return make_percent(numerator, denominator);
+       return (percent_range_t) make_percent(numerator, denominator);
 }
 
 static int _percent_run(struct dev_manager *dm, const char *name,
@@ -456,15 +510,15 @@ static int _percent_run(struct dev_manager *dm, const char *name,
        uint64_t start, length;
        char *type = NULL;
        char *params = NULL;
-       const struct dm_list *segh = &lv->segments;
+       const struct dm_list *segh = lv ? &lv->segments : NULL;
        struct lv_segment *seg = NULL;
        struct segment_type *segtype;
        int first_time = 1;
-       percent_t percent;
+       percent_t percent = PERCENT_INVALID;
 
        uint64_t total_numerator = 0, total_denominator = 0;
 
-       *overall_percent = PERCENT_INVALID;
+       *overall_percent = percent;
 
        if (!(dmt = _setup_task(name, dlid, event_nr,
                                wait ? DM_DEVICE_WAITEVENT : DM_DEVICE_STATUS, 0, 0)))
@@ -614,6 +668,11 @@ int dev_manager_transient(struct dev_manager *dm, struct logical_volume *lv)
                if (!type || !params)
                        continue;
 
+               if (!seg) {
+                       log_error(INTERNAL_ERROR "Segment is not selected.");
+                       goto out;
+               }
+
                if (seg->segtype->ops->check_transient_status &&
                    !seg->segtype->ops->check_transient_status(seg, params))
                        goto_out;
@@ -637,7 +696,8 @@ int dev_manager_transient(struct dev_manager *dm, struct logical_volume *lv)
  * dev_manager implementation.
  */
 struct dev_manager *dev_manager_create(struct cmd_context *cmd,
-                                      const char *vg_name)
+                                      const char *vg_name,
+                                      unsigned track_pvmove_deps)
 {
        struct dm_pool *mem;
        struct dev_manager *dm;
@@ -654,6 +714,12 @@ struct dev_manager *dev_manager_create(struct cmd_context *cmd,
        if (!(dm->vg_name = dm_pool_strdup(dm->mem, vg_name)))
                goto_bad;
 
+       /*
+        * When we manipulate (normally suspend/resume) the PVMOVE
+        * device directly, there's no need to touch the LVs above.
+        */
+       dm->track_pvmove_deps = track_pvmove_deps;
+
        dm->target_state = NULL;
 
        dm_udev_set_sync_support(cmd->current_settings.udev_sync);
@@ -684,6 +750,7 @@ int dev_manager_snapshot_percent(struct dev_manager *dm,
                                 const struct logical_volume *lv,
                                 percent_t *percent)
 {
+       const struct logical_volume *snap_lv;
        char *name;
        const char *dlid;
        int fail_if_percent_unsupported = 0;
@@ -703,13 +770,19 @@ int dev_manager_snapshot_percent(struct dev_manager *dm,
                fail_if_percent_unsupported = 1;
        }
 
+       if (lv_is_merging_cow(lv)) {
+               /* must check percent of origin for a merging snapshot */
+               snap_lv = origin_from_cow(lv);
+       } else
+               snap_lv = lv;
+
        /*
         * Build a name for the top layer.
         */
-       if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, NULL)))
+       if (!(name = dm_build_dm_name(dm->mem, snap_lv->vg->name, snap_lv->name, NULL)))
                return_0;
 
-       if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, NULL)))
+       if (!(dlid = build_dm_uuid(dm->mem, snap_lv->lvid.s, NULL)))
                return_0;
 
        /*
@@ -720,8 +793,6 @@ int dev_manager_snapshot_percent(struct dev_manager *dm,
                       NULL, fail_if_percent_unsupported)))
                return_0;
 
-       /* FIXME dm_pool_free ? */
-
        /* If the snapshot isn't available, percent will be -1 */
        return 1;
 }
@@ -734,23 +805,23 @@ int dev_manager_mirror_percent(struct dev_manager *dm,
 {
        char *name;
        const char *dlid;
+       const char *target_type = first_seg(lv)->segtype->name;
        const char *layer = (lv_is_origin(lv)) ? "real" : NULL;
 
        /*
         * Build a name for the top layer.
         */
-       if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
+       if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
                return_0;
 
-       /* FIXME dm_pool_free ? */
-
        if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer))) {
                log_error("dlid build failed for %s", lv->name);
                return 0;
        }
 
-       log_debug("Getting device mirror status percentage for %s", name);
-       if (!(_percent(dm, name, dlid, "mirror", wait, lv, percent,
+       log_debug("Getting device %s status percentage for %s",
+                 target_type, name);
+       if (!(_percent(dm, name, dlid, target_type, wait, lv, percent,
                       event_nr, 0)))
                return_0;
 
@@ -781,7 +852,7 @@ int dev_manager_mirror_percent(struct dev_manager *dm,
        /* Rename? */
                if ((suffix = strrchr(dl->dlid + sizeof(UUID_PREFIX) - 1, '-')))
                        suffix++;
-               new_name = build_dm_name(dm->mem, dm->vg_name, dl->lv->name,
+               new_name = dm_build_dm_name(dm->mem, dm->vg_name, dl->lv->name,
                                        suffix);
 
 static int _belong_to_vg(const char *vgname, const char *name)
@@ -816,6 +887,94 @@ static int _belong_to_vg(const char *vgname, const char *name)
 
 #endif
 
+int dev_manager_thin_pool_status(struct dev_manager *dm,
+                                const struct logical_volume *lv,
+                                struct dm_status_thin_pool **status)
+{
+       const char *dlid;
+       struct dm_task *dmt;
+       struct dm_info info;
+       uint64_t start, length;
+       char *type = NULL;
+       char *params = NULL;
+       int r = 0;
+
+       /* Build dlid for the thin pool layer */
+       if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, _thin_layer)))
+               return_0;
+
+       log_debug("Getting thin pool device status for %s.", lv->name);
+
+       if (!(dmt = _setup_task(NULL, dlid, 0, DM_DEVICE_STATUS, 0, 0)))
+               return_0;
+
+       if (!dm_task_no_open_count(dmt))
+               log_error("Failed to disable open_count.");
+
+       if (!dm_task_run(dmt))
+               goto_out;
+
+       if (!dm_task_get_info(dmt, &info) || !info.exists)
+               goto_out;
+
+       dm_get_next_target(dmt, NULL, &start, &length, &type, &params);
+
+       if (!dm_get_status_thin_pool(dm->mem, params, status))
+               goto_out;
+
+       r = 1;
+out:
+       dm_task_destroy(dmt);
+
+       return r;
+}
+
+int dev_manager_thin_pool_percent(struct dev_manager *dm,
+                                 const struct logical_volume *lv,
+                                 int metadata, percent_t *percent)
+{
+       char *name;
+       const char *dlid;
+
+       /* Build a name for the top layer */
+       if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name,
+                                     _thin_layer)))
+               return_0;
+
+       if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, _thin_layer)))
+               return_0;
+
+       log_debug("Getting device status percentage for %s", name);
+       if (!(_percent(dm, name, dlid, "thin-pool", 0,
+                      (metadata) ? lv : NULL, percent, NULL, 1)))
+               return_0;
+
+       return 1;
+}
+
+int dev_manager_thin_percent(struct dev_manager *dm,
+                            const struct logical_volume *lv,
+                            int mapped, percent_t *percent)
+{
+       char *name;
+       const char *dlid;
+       const char *layer = lv_is_origin(lv) ? "real" : NULL;
+
+       /* Build a name for the top layer */
+       if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
+               return_0;
+
+       if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer)))
+               return_0;
+
+       log_debug("Getting device status percentage for %s", name);
+       if (!(_percent(dm, name, dlid, "thin", 0,
+                      (mapped) ? NULL : lv, percent, NULL, 1)))
+               return_0;
+
+       return 1;
+}
+
 /*************************/
 /*  NEW CODE STARTS HERE */
 /*************************/
@@ -824,7 +983,7 @@ static int _dev_manager_lv_mknodes(const struct logical_volume *lv)
 {
        char *name;
 
-       if (!(name = build_dm_name(lv->vg->cmd->mem, lv->vg->name,
+       if (!(name = dm_build_dm_name(lv->vg->cmd->mem, lv->vg->name,
                                   lv->name, NULL)))
                return_0;
 
@@ -842,7 +1001,7 @@ int dev_manager_mknodes(const struct logical_volume *lv)
        char *name;
        int r = 0;
 
-       if (!(name = build_dm_name(lv->vg->cmd->mem, lv->vg->name, lv->name, NULL)))
+       if (!(name = dm_build_dm_name(lv->vg->cmd->mem, lv->vg->name, lv->name, NULL)))
                return_0;
 
        if ((r = _info_run(name, NULL, &dminfo, NULL, 1, 0, 0, 0, 0))) {
@@ -862,11 +1021,19 @@ static uint16_t _get_udev_flags(struct dev_manager *dm, struct logical_volume *l
 {
        uint16_t udev_flags = 0;
 
+       /*
+        * Instruct also libdevmapper to disable udev
+        * fallback in accordance to LVM2 settings.
+        */
+       if (!dm->cmd->current_settings.udev_fallback)
+               udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
+
        /*
         * Is this top-level and visible device?
         * If not, create just the /dev/mapper content.
         */
-       if (layer || !lv_is_visible(lv))
+       /* FIXME: add target's method for this */
+       if (layer || !lv_is_visible(lv) || lv_is_thin_pool(lv))
                udev_flags |= DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG |
                              DM_UDEV_DISABLE_DISK_RULES_FLAG |
                              DM_UDEV_DISABLE_OTHER_RULES_FLAG;
@@ -907,7 +1074,7 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
        char *dlid, *name;
        struct dm_info info, info2;
 
-       if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
+       if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
                return_0;
 
        if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer)))
@@ -1031,12 +1198,132 @@ static int _add_partial_replicator_to_dtree(struct dev_manager *dm,
        return 1;
 }
 
+struct thin_cb_data {
+       const struct logical_volume *pool_lv;
+       struct dev_manager *dm;
+};
+
+static int _thin_pool_callback(struct dm_tree_node *node,
+                              dm_node_callback_t type, void *cb_data)
+{
+       int ret, status;
+       const struct thin_cb_data *data = cb_data;
+       const char *dmdir = dm_dir();
+       const struct dm_config_node *cn;
+       const struct dm_config_value *cv;
+       const char *thin_check =
+               find_config_tree_str_allow_empty(data->pool_lv->vg->cmd,
+                                                "global/thin_check_executable",
+                                                THIN_CHECK_CMD);
+       const struct logical_volume *mlv = first_seg(data->pool_lv)->metadata_lv;
+       size_t len = strlen(dmdir) + 2 * (strlen(mlv->vg->name) + strlen(mlv->name)) + 3;
+       char meta_path[len];
+       int args = 0;
+       const char *argv[19]; /* Max supported 15 args */
+       char *split, *dm_name;
+
+       if (!thin_check[0])
+               return 1; /* Checking disabled */
+
+       if (!(dm_name = dm_build_dm_name(data->dm->mem, mlv->vg->name,
+                                        mlv->name, NULL)) ||
+           (dm_snprintf(meta_path, len, "%s/%s", dmdir, dm_name) < 0)) {
+               log_error("Failed to build thin metadata path.");
+               return 0;
+       }
+
+       if ((cn = find_config_tree_node(mlv->vg->cmd, "global/thin_check_options"))) {
+               for (cv = cn->v; cv && args < 16; cv = cv->next) {
+                       if (cv->type != DM_CFG_STRING) {
+                               log_error("Invalid string in config file: "
+                                         "global/thin_check_options");
+                               return 0;
+                       }
+                       argv[++args] = cv->v.str;
+               }
+       } else {
+               /* Use default options (no support for options with spaces) */
+               if (!(split = dm_pool_strdup(data->dm->mem, DEFAULT_THIN_CHECK_OPTIONS))) {
+                       log_error("Failed to duplicate thin check string.");
+                       return 0;
+               }
+               args = dm_split_words(split, 16, 0, (char**) argv + 1);
+       }
+
+       if (args == 16) {
+               log_error("Too many options for thin check command.");
+               return 0;
+       }
+
+       argv[0] = thin_check;
+       argv[++args] = meta_path;
+       argv[++args] = NULL;
+
+       if (!(ret = exec_cmd(data->pool_lv->vg->cmd, (const char * const *)argv,
+                            &status, 0))) {
+               switch (type) {
+               case DM_NODE_CALLBACK_PRELOADED:
+                       log_err_once("Check of thin pool %s/%s failed (status:%d). "
+                                    "Manual repair required (thin_dump --repair %s)!",
+                                    data->pool_lv->vg->name, data->pool_lv->name,
+                                    status, meta_path);
+                       break;
+               default:
+                       log_warn("WARNING: Integrity check of metadata for thin pool "
+                                "%s/%s failed.",
+                                data->pool_lv->vg->name, data->pool_lv->name);
+               }
+               /*
+                * FIXME: What should we do here??
+                *
+                * Maybe mark the node, so it's not activating
+                * as thin_pool but as error/linear and let the
+                * dm tree resolve the issue.
+                */
+       }
+
+       dm_pool_free(data->dm->mem, dm_name);
+
+       return ret;
+}
+
+static int _thin_pool_register_callback(struct dev_manager *dm,
+                                       struct dm_tree_node *node,
+                                       const struct logical_volume *lv)
+{
+       struct thin_cb_data *data;
+
+       /* Skip metadata testing for unused pool. */
+       if (!first_seg(lv)->transaction_id)
+               return 1;
+
+       if (!(data = dm_pool_alloc(dm->mem, sizeof(*data)))) {
+               log_error("Failed to allocated path for callback.");
+               return 0;
+       }
+
+       data->dm = dm;
+       data->pool_lv = lv;
+
+       dm_tree_node_set_callback(node, _thin_pool_callback, data);
+
+       return 1;
+}
+
 /*
  * Add LV and any known dependencies
  */
-static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, struct logical_volume *lv, unsigned origin_only)
+static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
+                           struct logical_volume *lv, int origin_only)
 {
-       if (!origin_only && !_add_dev_to_dtree(dm, dtree, lv, NULL))
+       uint32_t s;
+       struct seg_list *sl;
+       struct lv_segment *seg = first_seg(lv);
+       struct dm_tree_node *thin_node;
+       const char *uuid;
+
+       if ((!origin_only || lv_is_thin_volume(lv)) &&
+           !_add_dev_to_dtree(dm, dtree, lv, NULL))
                return_0;
 
        /* FIXME Can we avoid doing this every time? */
@@ -1046,36 +1333,79 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, struc
        if (!origin_only && !_add_dev_to_dtree(dm, dtree, lv, "cow"))
                return_0;
 
-       if ((lv->status & MIRRORED) && first_seg(lv)->log_lv &&
-           !_add_dev_to_dtree(dm, dtree, first_seg(lv)->log_lv, NULL))
+       if ((lv->status & MIRRORED) && seg->log_lv &&
+           !_add_dev_to_dtree(dm, dtree, seg->log_lv, NULL))
                return_0;
 
+       if (lv->status & RAID)
+               for (s = 0; s < seg->area_count; s++)
+                       if (!_add_dev_to_dtree(dm, dtree,
+                                              seg_metalv(seg, s), NULL))
+                               return_0;
+
+       /* Add any LVs referencing a PVMOVE LV unless told not to. */
+       if (dm->track_pvmove_deps && lv->status & PVMOVE)
+               dm_list_iterate_items(sl, &lv->segs_using_this_lv)
+                       if (!_add_lv_to_dtree(dm, dtree, sl->seg->lv, origin_only))
+                               return_0;
+
        /* Adding LV head of replicator adds all other related devs */
        if (lv_is_replicator_dev(lv) &&
            !_add_partial_replicator_to_dtree(dm, dtree, lv))
                return_0;
 
+       if (lv_is_thin_volume(lv)) {
+#if 0
+               /* FIXME Implement dm_tree_node_skip_children optimisation */
+               if (origin_only) {
+                       if (!(uuid = build_dm_uuid(dm->mem, lv->lvid.s, NULL)))
+                               return_0;
+                       if ((thin_node = dm_tree_find_node_by_uuid(dtree, uuid)))
+                               dm_tree_node_skip_children(thin_node, 1);
+               }
+#endif
+               /* Add thin pool LV layer */
+               lv = seg->pool_lv;
+               seg = first_seg(lv);
+       }
+
+       if (!origin_only && lv_is_thin_pool(lv)) {
+               if (!_add_lv_to_dtree(dm, dtree, seg->metadata_lv, 0))
+                       return_0;
+               /* FIXME code from _create_partial_dtree() should be moved here */
+               if (!_add_lv_to_dtree(dm, dtree, seg_lv(seg, 0), 0))
+                       return_0;
+               if (!_add_dev_to_dtree(dm, dtree, lv, _thin_layer))
+                       return_0;
+               /* If the partial tree is used for deactivation, setup callback */
+               if (!(uuid = build_dm_uuid(dm->mem, lv->lvid.s, _thin_layer)))
+                       return_0;
+               if ((thin_node = dm_tree_find_node_by_uuid(dtree, uuid)) &&
+                   !_thin_pool_register_callback(dm, thin_node, lv))
+                       return_0;
+       }
+
        return 1;
 }
 
-static struct dm_tree *_create_partial_dtree(struct dev_manager *dm, struct logical_volume *lv, unsigned origin_only)
+static struct dm_tree *_create_partial_dtree(struct dev_manager *dm, struct logical_volume *lv, int origin_only)
 {
        struct dm_tree *dtree;
-       struct dm_list *snh, *snht;
+       struct dm_list *snh;
        struct lv_segment *seg;
        uint32_t s;
 
        if (!(dtree = dm_tree_create())) {
-               log_error("Partial dtree creation failed for %s.", lv->name);
+               log_debug("Partial dtree creation failed for %s.", lv->name);
                return NULL;
        }
 
-       if (!_add_lv_to_dtree(dm, dtree, lv, origin_only))
+       if (!_add_lv_to_dtree(dm, dtree, lv, (lv_is_origin(lv) || lv_is_thin_volume(lv)) ? origin_only : 0))
                goto_bad;
 
        /* Add any snapshots of this LV */
-       if (!origin_only)
-               dm_list_iterate_safe(snh, snht, &lv->snapshot_segs)
+       if (!origin_only && lv_is_origin(lv))
+               dm_list_iterate(snh, &lv->snapshot_segs)
                        if (!_add_lv_to_dtree(dm, dtree, dm_list_struct_base(snh, struct lv_segment, origin_list)->cow, 0))
                                goto_bad;
 
@@ -1097,12 +1427,13 @@ bad:
 static char *_add_error_device(struct dev_manager *dm, struct dm_tree *dtree,
                               struct lv_segment *seg, int s)
 {
-       char *id, *name;
+       char *dlid, *name;
        char errid[32];
        struct dm_tree_node *node;
        struct lv_segment *seg_i;
-       int segno = -1, i = 0;;
-       uint64_t size = seg->len * seg->lv->vg->extent_size;
+       struct dm_info info;
+       int segno = -1, i = 0;
+       uint64_t size = (uint64_t) seg->len * seg->lv->vg->extent_size;
 
        dm_list_iterate_items(seg_i, &seg->lv->segments) {
                if (seg == seg_i)
@@ -1112,23 +1443,40 @@ static char *_add_error_device(struct dev_manager *dm, struct dm_tree *dtree,
 
        if (segno < 0) {
                log_error("_add_error_device called with bad segment");
-               return_NULL;
+               return NULL;
        }
 
        sprintf(errid, "missing_%d_%d", segno, s);
 
-       if (!(id = build_dm_uuid(dm->mem, seg->lv->lvid.s, errid)))
+       if (!(dlid = build_dm_uuid(dm->mem, seg->lv->lvid.s, errid)))
                return_NULL;
 
-       if (!(name = build_dm_name(dm->mem, seg->lv->vg->name,
+       if (!(name = dm_build_dm_name(dm->mem, seg->lv->vg->name,
                                   seg->lv->name, errid)))
                return_NULL;
-       if (!(node = dm_tree_add_new_dev(dtree, name, id, 0, 0, 0, 0, 0)))
-               return_NULL;
-       if (!dm_tree_node_add_error_target(node, size))
-               return_NULL;
 
-       return id;
+       log_debug("Getting device info for %s [%s]", name, dlid);
+       if (!_info(dlid, 1, 0, &info, NULL)) {
+               log_error("Failed to get info for %s [%s].", name, dlid);
+               return 0;
+       }
+
+       if (!info.exists) {
+               /* Create new node */
+               if (!(node = dm_tree_add_new_dev(dtree, name, dlid, 0, 0, 0, 0, 0)))
+                       return_NULL;
+               if (!dm_tree_node_add_error_target(node, size))
+                       return_NULL;
+       } else {
+               /* Already exists */
+               if (!dm_tree_add_dev(dtree, info.major, info.minor)) {
+                       log_error("Failed to add device (%" PRIu32 ":%" PRIu32") to dtree",
+                                 info.major, info.minor);
+                       return_NULL;
+               }
+       }
+
+       return dlid;
 }
 
 static int _add_error_area(struct dev_manager *dm, struct dm_tree_node *node,
@@ -1143,15 +1491,13 @@ static int _add_error_area(struct dev_manager *dm, struct dm_tree_node *node,
                 * we don't have the struct definition available.
                 */
                struct dm_tree **tree = (struct dm_tree **) node;
-               dlid = _add_error_device(dm, *tree, seg, s);
-               if (!dlid)
+               if (!(dlid = _add_error_device(dm, *tree, seg, s)))
+                       return_0;
+               if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_le(seg, s)))
                        return_0;
-               dm_tree_node_add_target_area(node, NULL, dlid,
-                                            extent_size * seg_le(seg, s));
        } else
-               dm_tree_node_add_target_area(node,
-                                            dm->cmd->stripe_filler,
-                                            NULL, UINT64_C(0));
+               if (!dm_tree_node_add_target_area(node, dm->cmd->stripe_filler, NULL, UINT64_C(0)))
+                       return_0;
 
        return 1;
 }
@@ -1163,28 +1509,68 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
        uint64_t extent_size = seg->lv->vg->extent_size;
        uint32_t s;
        char *dlid;
+       struct stat info;
+       const char *name;
+       unsigned num_error_areas = 0;
+       unsigned num_existing_areas = 0;
 
+       /* FIXME Avoid repeating identical stat in dm_tree_node_add_target_area */
        for (s = start_area; s < areas; s++) {
                if ((seg_type(seg, s) == AREA_PV &&
-                    (!seg_pvseg(seg, s) ||
-                     !seg_pv(seg, s) ||
-                     !seg_dev(seg, s))) ||
+                    (!seg_pvseg(seg, s) || !seg_pv(seg, s) || !seg_dev(seg, s) ||
+                      !(name = dev_name(seg_dev(seg, s))) || !*name ||
+                      stat(name, &info) < 0 || !S_ISBLK(info.st_mode))) ||
                    (seg_type(seg, s) == AREA_LV && !seg_lv(seg, s))) {
+                       if (!seg->lv->vg->cmd->partial_activation) {
+                               log_error("Aborting.  LV %s is now incomplete "
+                                         "and --partial was not specified.", seg->lv->name);
+                               return 0;
+                       }
                        if (!_add_error_area(dm, node, seg, s))
                                return_0;
-               } else if (seg_type(seg, s) == AREA_PV)
-                       dm_tree_node_add_target_area(node,
-                                                       dev_name(seg_dev(seg, s)),
-                                                       NULL,
-                                                       (seg_pv(seg, s)->pe_start +
-                                                        (extent_size * seg_pe(seg, s))));
-               else if (seg_type(seg, s) == AREA_LV) {
-                       if (!(dlid = build_dm_uuid(dm->mem,
-                                                  seg_lv(seg, s)->lvid.s,
-                                                  NULL)))
+                       num_error_areas++;
+               } else if (seg_type(seg, s) == AREA_PV) {
+                       if (!dm_tree_node_add_target_area(node, dev_name(seg_dev(seg, s)), NULL,
+                                   (seg_pv(seg, s)->pe_start + (extent_size * seg_pe(seg, s)))))
+                               return_0;
+                       num_existing_areas++;
+               } else if (seg_is_raid(seg)) {
+                       /*
+                        * RAID can handle unassigned areas.  It simple puts
+                        * '- -' in for the metadata/data device pair.  This
+                        * is a valid way to indicate to the RAID target that
+                        * the device is missing.
+                        *
+                        * If an image is marked as VISIBLE_LV and !LVM_WRITE,
+                        * it means the device has temporarily been extracted
+                        * from the array.  It may come back at a future date,
+                        * so the bitmap must track differences.  Again, '- -'
+                        * is used in the CTR table.
+                        */
+                       if ((seg_type(seg, s) == AREA_UNASSIGNED) ||
+                           ((seg_lv(seg, s)->status & VISIBLE_LV) &&
+                            !(seg_lv(seg, s)->status & LVM_WRITE))) {
+                               /* One each for metadata area and data area */
+                               if (!dm_tree_node_add_null_area(node, 0) ||
+                                   !dm_tree_node_add_null_area(node, 0))
+                                       return_0;
+                               continue;
+                       }
+                       if (!(dlid = build_dm_uuid(dm->mem, seg_metalv(seg, s)->lvid.s, NULL)))
+                               return_0;
+                       if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_metale(seg, s)))
+                               return_0;
+
+                       if (!(dlid = build_dm_uuid(dm->mem, seg_lv(seg, s)->lvid.s, NULL)))
+                               return_0;
+                       if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_le(seg, s)))
+                               return_0;
+               } else if (seg_type(seg, s) == AREA_LV) {
+
+                       if (!(dlid = build_dm_uuid(dm->mem, seg_lv(seg, s)->lvid.s, NULL)))
+                               return_0;
+                       if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_le(seg, s)))
                                return_0;
-                       dm_tree_node_add_target_area(node, NULL, dlid,
-                                                       extent_size * seg_le(seg, s));
                } else {
                        log_error(INTERNAL_ERROR "Unassigned area found in LV %s.",
                                  seg->lv->name);
@@ -1192,6 +1578,15 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
                }
        }
 
+        if (num_error_areas) {
+               /* Thins currently do not support partial activation */
+               if (lv_is_thin_type(seg->lv)) {
+                       log_error("Cannot activate %s%s: pool incomplete.",
+                                 seg->lv->vg->name, seg->lv->name);
+                       return 0;
+               }
+       }
+
        return 1;
 }
 
@@ -1235,8 +1630,9 @@ static int _add_snapshot_merge_target_to_dtree(struct dev_manager *dm,
 }
 
 static int _add_snapshot_target_to_dtree(struct dev_manager *dm,
-                                          struct dm_tree_node *dnode,
-                                          struct logical_volume *lv)
+                                        struct dm_tree_node *dnode,
+                                        struct logical_volume *lv,
+                                        struct lv_activate_opts *laopts)
 {
        const char *origin_dlid;
        const char *cow_dlid;
@@ -1256,7 +1652,7 @@ static int _add_snapshot_target_to_dtree(struct dev_manager *dm,
 
        size = (uint64_t) snap_seg->len * snap_seg->origin->vg->extent_size;
 
-       if (lv_is_merging_cow(lv)) {
+       if (!laopts->no_merging && lv_is_merging_cow(lv)) {
                /* cow is to be merged so load the error target */
                if (!dm_tree_node_add_error_target(dnode, size))
                        return_0;
@@ -1269,8 +1665,9 @@ static int _add_snapshot_target_to_dtree(struct dev_manager *dm,
 }
 
 static int _add_target_to_dtree(struct dev_manager *dm,
-                                 struct dm_tree_node *dnode,
-                                 struct lv_segment *seg)
+                               struct dm_tree_node *dnode,
+                               struct lv_segment *seg,
+                               struct lv_activate_opts *laopts)
 {
        uint64_t extent_size = seg->lv->vg->extent_size;
 
@@ -1282,47 +1679,52 @@ static int _add_target_to_dtree(struct dev_manager *dm,
 
        return seg->segtype->ops->add_target_line(dm, dm->mem, dm->cmd,
                                                  &dm->target_state, seg,
-                                                 dnode,
+                                                 laopts, dnode,
                                                  extent_size * seg->len,
                                                  &dm-> pvmove_mirror_count);
 }
 
 static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
-                                 struct logical_volume *lv, const char *layer);
+                               struct logical_volume *lv,
+                               struct lv_activate_opts *laopts,
+                               const char *layer);
 
 /* Add all replicators' LVs */
 static int _add_replicator_dev_target_to_dtree(struct dev_manager *dm,
                                               struct dm_tree *dtree,
-                                              struct lv_segment *seg)
+                                              struct lv_segment *seg,
+                                              struct lv_activate_opts *laopts)
 {
        struct replicator_device *rdev;
        struct replicator_site *rsite;
 
        /* For inactive replicator add linear mapping */
        if (!lv_is_active_replicator_dev(seg->lv)) {
-               if (!_add_new_lv_to_dtree(dm, dtree, seg->lv->rdevice->lv, NULL))
+               if (!_add_new_lv_to_dtree(dm, dtree, seg->lv->rdevice->lv, laopts, NULL))
                        return_0;
                return 1;
        }
 
        /* Add rlog and replicator nodes */
        if (!seg->replicator ||
-            !first_seg(seg->replicator)->rlog_lv ||
+           !first_seg(seg->replicator)->rlog_lv ||
            !_add_new_lv_to_dtree(dm, dtree,
-                                 first_seg(seg->replicator)->rlog_lv, NULL) ||
-           !_add_new_lv_to_dtree(dm, dtree, seg->replicator, NULL))
+                                 first_seg(seg->replicator)->rlog_lv,
+                                 laopts, NULL) ||
+           !_add_new_lv_to_dtree(dm, dtree, seg->replicator, laopts, NULL))
            return_0;
 
        /* Activation of one replicator_dev node activates all other nodes */
        dm_list_iterate_items(rsite, &seg->replicator->rsites) {
                dm_list_iterate_items(rdev, &rsite->rdevices) {
                        if (rdev->lv &&
-                           !_add_new_lv_to_dtree(dm, dtree, rdev->lv, NULL))
+                           !_add_new_lv_to_dtree(dm, dtree, rdev->lv,
+                                                 laopts, NULL))
                                return_0;
 
                        if (rdev->slog &&
-                           !_add_new_lv_to_dtree(dm, dtree,
-                                                 rdev->slog, NULL))
+                           !_add_new_lv_to_dtree(dm, dtree, rdev->slog,
+                                                 laopts, NULL))
                                return_0;
                }
        }
@@ -1337,7 +1739,7 @@ static int _add_replicator_dev_target_to_dtree(struct dev_manager *dm,
                        if (!rdev->replicator_dev->lv ||
                            !_add_new_lv_to_dtree(dm, dtree,
                                                  rdev->replicator_dev->lv,
-                                                 NULL))
+                                                 laopts, NULL))
                                return_0;
                }
        }
@@ -1346,20 +1748,22 @@ static int _add_replicator_dev_target_to_dtree(struct dev_manager *dm,
 }
 
 static int _add_segment_to_dtree(struct dev_manager *dm,
-                                  struct dm_tree *dtree,
-                                  struct dm_tree_node *dnode,
-                                  struct lv_segment *seg,
-                                  const char *layer)
+                                struct dm_tree *dtree,
+                                struct dm_tree_node *dnode,
+                                struct lv_segment *seg,
+                                struct lv_activate_opts *laopts,
+                                const char *layer)
 {
        uint32_t s;
        struct dm_list *snh;
        struct lv_segment *seg_present;
        const char *target_name;
+       struct lv_activate_opts lva;
 
        /* Ensure required device-mapper targets are loaded */
        seg_present = find_cow(seg->lv) ? : seg;
        target_name = (seg_present->segtype->ops->target_name ?
-                      seg_present->segtype->ops->target_name(seg_present) :
+                      seg_present->segtype->ops->target_name(seg_present, laopts) :
                       seg_present->segtype->name);
 
        log_debug("Checking kernel supports %s segment type for %s%s%s",
@@ -1376,45 +1780,56 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
 
        /* Add mirror log */
        if (seg->log_lv &&
-           !_add_new_lv_to_dtree(dm, dtree, seg->log_lv, NULL))
+           !_add_new_lv_to_dtree(dm, dtree, seg->log_lv, laopts, NULL))
                return_0;
 
        if (seg_is_replicator_dev(seg)) {
-               if (!_add_replicator_dev_target_to_dtree(dm, dtree, seg))
+               if (!_add_replicator_dev_target_to_dtree(dm, dtree, seg, laopts))
                        return_0;
        /* If this is a snapshot origin, add real LV */
        /* If this is a snapshot origin + merging snapshot, add cow + real LV */
        } else if (lv_is_origin(seg->lv) && !layer) {
-               if (vg_is_clustered(seg->lv->vg)) {
-                       log_error("Clustered snapshots are not yet supported");
-                       return 0;
-               }
-               if (lv_is_merging_origin(seg->lv)) {
+               if (!laopts->no_merging && lv_is_merging_origin(seg->lv)) {
                        if (!_add_new_lv_to_dtree(dm, dtree,
-                            find_merging_cow(seg->lv)->cow, "cow"))
+                            find_merging_cow(seg->lv)->cow, laopts, "cow"))
                                return_0;
                        /*
                         * Must also add "real" LV for use when
                         * snapshot-merge target is added
                         */
                }
-               if (!_add_new_lv_to_dtree(dm, dtree, seg->lv, "real"))
+               if (!_add_new_lv_to_dtree(dm, dtree, seg->lv, laopts, "real"))
                        return_0;
        } else if (lv_is_cow(seg->lv) && !layer) {
-               if (!_add_new_lv_to_dtree(dm, dtree, seg->lv, "cow"))
+               if (!_add_new_lv_to_dtree(dm, dtree, seg->lv, laopts, "cow"))
+                       return_0;
+       } else if ((layer != _thin_layer) && seg_is_thin(seg)) {
+               lva = *laopts;
+               lva.real_pool = 1;
+               if (!_add_new_lv_to_dtree(dm, dtree, seg_is_thin_pool(seg) ?
+                                         seg->lv : seg->pool_lv, &lva, _thin_layer))
                        return_0;
        } else {
+               if (seg_is_thin_pool(seg) &&
+                   !_add_new_lv_to_dtree(dm, dtree, seg->metadata_lv, laopts, NULL))
+                       return_0;
+
                /* Add any LVs used by this segment */
-               for (s = 0; s < seg->area_count; s++)
+               for (s = 0; s < seg->area_count; s++) {
                        if ((seg_type(seg, s) == AREA_LV) &&
                            (!_add_new_lv_to_dtree(dm, dtree, seg_lv(seg, s),
-                                                  NULL)))
+                                                  laopts, NULL)))
                                return_0;
+                       if (seg_is_raid(seg) &&
+                           !_add_new_lv_to_dtree(dm, dtree, seg_metalv(seg, s),
+                                                 laopts, NULL))
+                               return_0;
+               }
        }
 
        /* Now we've added its dependencies, we can add the target itself */
        if (lv_is_origin(seg->lv) && !layer) {
-               if (!lv_is_merging_origin(seg->lv)) {
+               if (laopts->no_merging || !lv_is_merging_origin(seg->lv)) {
                        if (!_add_origin_target_to_dtree(dm, dnode, seg->lv))
                                return_0;
                } else {
@@ -1422,25 +1837,79 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
                                return_0;
                }
        } else if (lv_is_cow(seg->lv) && !layer) {
-               if (!_add_snapshot_target_to_dtree(dm, dnode, seg->lv))
+               if (!_add_snapshot_target_to_dtree(dm, dnode, seg->lv, laopts))
                        return_0;
-       } else if (!_add_target_to_dtree(dm, dnode, seg))
+       } else if (!_add_target_to_dtree(dm, dnode, seg, laopts))
                return_0;
 
        if (lv_is_origin(seg->lv) && !layer)
                /* Add any snapshots of this LV */
                dm_list_iterate(snh, &seg->lv->snapshot_segs)
-                       if (!_add_new_lv_to_dtree(dm, dtree, dm_list_struct_base(snh, struct lv_segment, origin_list)->cow, NULL))
+                       if (!_add_new_lv_to_dtree(dm, dtree, dm_list_struct_base(snh, struct lv_segment, origin_list)->cow,
+                                                 laopts, NULL))
                                return_0;
 
        return 1;
 }
 
+static int _set_udev_flags_for_children(struct dev_manager *dm,
+                                       struct volume_group *vg,
+                                       struct dm_tree_node *dnode)
+{
+       char *p;
+       const char *uuid;
+       void *handle = NULL;
+       struct dm_tree_node *child;
+       const struct dm_info *info;
+       struct lv_list *lvl;
+
+       while ((child = dm_tree_next_child(&handle, dnode, 0))) {
+               /* Ignore root node */
+               if (!(info  = dm_tree_node_get_info(child)) || !info->exists)
+                       continue;
+
+               if (!(uuid = dm_tree_node_get_uuid(child))) {
+                       log_error(INTERNAL_ERROR
+                                 "Failed to get uuid for %" PRIu32 ":%" PRIu32,
+                                 info->major, info->minor);
+                       continue;
+               }
+
+               /* Ignore non-LVM devices */
+               if (!(p = strstr(uuid, UUID_PREFIX)))
+                       continue;
+               p += strlen(UUID_PREFIX);
+
+               /* Ignore LVs that belong to different VGs (due to stacking) */
+               if (strncmp(p, (char *)vg->id.uuid, ID_LEN))
+                       continue;
+
+               /* Ignore LVM devices with 'layer' suffixes */
+               if (strrchr(p, '-'))
+                       continue;
+
+               if (!(lvl = find_lv_in_vg_by_lvid(vg, (const union lvid *)p))) {
+                       log_error(INTERNAL_ERROR
+                                 "%s (%" PRIu32 ":%" PRIu32 ") not found in VG",
+                                 dm_tree_node_get_name(child),
+                                 info->major, info->minor);
+                       return 0;
+               }
+
+               dm_tree_node_set_udev_flags(child,
+                                           _get_udev_flags(dm, lvl->lv, NULL));
+       }
+
+       return 1;
+}
+
 static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
-                                 struct logical_volume *lv, const char *layer)
+                               struct logical_volume *lv, struct lv_activate_opts *laopts,
+                               const char *layer)
 {
        struct lv_segment *seg;
        struct lv_layer *lvlayer;
+       struct seg_list *sl;
        struct dm_tree_node *dnode;
        const struct dm_info *dinfo;
        char *name, *dlid;
@@ -1464,11 +1933,11 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
                                           dtree)) && dinfo->open_count)) {
                        /* FIXME Is there anything simpler to check for instead? */
                        if (!lv_has_target_type(dm->mem, lv, NULL, "snapshot-merge"))
-                               clear_snapshot_merge(lv);
+                               laopts->no_merging = 1;
                }
        }
 
-       if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
+       if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
                return_0;
 
        if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, layer)))
@@ -1493,11 +1962,14 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
         * existing inactive table left behind.
         * Major/minor settings only apply to the visible layer.
         */
+       /* FIXME Move the clear from here until later, so we can leave
+        * identical inactive tables untouched. (For pvmove.)
+        */
        if (!(dnode = dm_tree_add_new_dev_with_udev_flags(dtree, name, dlid,
                                             layer ? UINT32_C(0) : (uint32_t) lv->major,
                                             layer ? UINT32_C(0) : (uint32_t) lv->minor,
-                                            _read_only_lv(lv),
-                                            (lv->vg->status & PRECOMMITTED) ? 1 : 0,
+                                            read_only_lv(lv, laopts),
+                                            ((lv->vg->status & PRECOMMITTED) | laopts->revert) ? 1 : 0,
                                             lvlayer,
                                             _get_udev_flags(dm, lv, layer))))
                return_0;
@@ -1508,12 +1980,12 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
        /* Create table */
        dm->pvmove_mirror_count = 0u;
        dm_list_iterate_items(seg, &lv->segments) {
-               if (!_add_segment_to_dtree(dm, dtree, dnode, seg, layer))
+               if (!_add_segment_to_dtree(dm, dtree, dnode, seg, laopts, layer))
                        return_0;
                /* These aren't real segments in the LVM2 metadata */
                if (lv_is_origin(lv) && !layer)
                        break;
-               if (lv_is_cow(lv) && !layer)
+               if (!laopts->no_merging && lv_is_cow(lv) && !layer)
                        break;
                if (max_stripe_size < seg->stripe_size * seg->area_count)
                        max_stripe_size = seg->stripe_size * seg->area_count;
@@ -1529,6 +2001,20 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
 
        dm_tree_node_set_read_ahead(dnode, read_ahead, read_ahead_flags);
 
+       /* Setup thin pool callback */
+       if (layer && lv_is_thin_pool(lv) &&
+           !_thin_pool_register_callback(dm, dnode, lv))
+               return_0;
+
+       /* Add any LVs referencing a PVMOVE LV unless told not to */
+       if (dm->track_pvmove_deps && (lv->status & PVMOVE))
+               dm_list_iterate_items(sl, &lv->segs_using_this_lv)
+                       if (!_add_new_lv_to_dtree(dm, dtree, sl->seg->lv, laopts, NULL))
+                               return_0;
+
+       if (!_set_udev_flags_for_children(dm, lv->vg, dnode))
+               return_0;
+
        return 1;
 }
 
@@ -1549,6 +2035,12 @@ static int _create_lv_symlinks(struct dev_manager *dm, struct dm_tree_node *root
        const char *name;
        int r = 1;
 
+       /* Nothing to do if udev fallback is disabled. */
+       if (!dm->cmd->current_settings.udev_fallback) {
+               fs_set_create();
+               return 1;
+       }
+
        while ((child = dm_tree_next_child(&handle, root, 0))) {
                if (!(lvlayer = dm_tree_node_get_context(child)))
                        continue;
@@ -1591,6 +2083,10 @@ static int _remove_lv_symlinks(struct dev_manager *dm, struct dm_tree_node *root
        char *vgname, *lvname, *layer;
        int r = 1;
 
+       /* Nothing to do if udev fallback is disabled. */
+       if (!dm->cmd->current_settings.udev_fallback)
+               return 1;
+
        while ((child = dm_tree_next_child(&handle, root, 0))) {
                if (!dm_split_lvm_name(dm->mem, dm_tree_node_get_name(child), &vgname, &lvname, &layer)) {
                        r = 0;
@@ -1617,7 +2113,6 @@ static int _clean_tree(struct dev_manager *dm, struct dm_tree_node *root, char *
        struct dm_tree_node *child;
        char *vgname, *lvname, *layer;
        const char *name, *uuid;
-       int r;
 
        while ((child = dm_tree_next_child(&handle, root, 0))) {
                if (!(name = dm_tree_node_get_name(child)))
@@ -1639,12 +2134,7 @@ static int _clean_tree(struct dev_manager *dm, struct dm_tree_node *root, char *
                if (non_toplevel_tree_dlid && !strcmp(non_toplevel_tree_dlid, uuid))
                        continue;
 
-               dm_tree_set_cookie(root, 0);
-               r = dm_tree_deactivate_children(root, uuid, strlen(uuid));
-               if (!dm_udev_wait(dm_tree_get_cookie(root)))
-                       stack;
-
-               if (!r)
+               if (!dm_tree_deactivate_children(root, uuid, strlen(uuid)))
                        return_0;
        }
 
@@ -1652,78 +2142,74 @@ static int _clean_tree(struct dev_manager *dm, struct dm_tree_node *root, char *
 }
 
 static int _tree_action(struct dev_manager *dm, struct logical_volume *lv,
-                       unsigned origin_only, action_t action)
+                       struct lv_activate_opts *laopts, action_t action)
 {
+       const size_t DLID_SIZE = ID_LEN + sizeof(UUID_PREFIX) - 1;
        struct dm_tree *dtree;
        struct dm_tree_node *root;
        char *dlid;
        int r = 0;
 
-       if (!(dtree = _create_partial_dtree(dm, lv, origin_only)))
+       laopts->is_activate = (action == ACTIVATE);
+
+       if (!(dtree = _create_partial_dtree(dm, lv, laopts->origin_only)))
                return_0;
 
        if (!(root = dm_tree_find_node(dtree, 0, 0))) {
                log_error("Lost dependency tree root node");
-               goto out;
+               goto out_no_root;
        }
 
-       if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, origin_only ? "real" : NULL)))
+       /* Restore fs cookie */
+       dm_tree_set_cookie(root, fs_get_cookie());
+
+       if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, (lv_is_origin(lv) && laopts->origin_only) ? "real" : NULL)))
                goto_out;
 
        /* Only process nodes with uuid of "LVM-" plus VG id. */
        switch(action) {
        case CLEAN:
                /* Deactivate any unused non-toplevel nodes */
-               if (!_clean_tree(dm, root, origin_only ? dlid : NULL))
+               if (!_clean_tree(dm, root, laopts->origin_only ? dlid : NULL))
                        goto_out;
                break;
        case DEACTIVATE:
-               /* Deactivate LV and all devices it references that nothing else has open. */
-               dm_tree_set_cookie(root, 0);
-               r = dm_tree_deactivate_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1);
-               if (!dm_udev_wait(dm_tree_get_cookie(root)))
-                       stack;
-               if (!r)
+               if (retry_deactivation())
+                       dm_tree_retry_remove(root);
+               /* Deactivate LV and all devices it references that nothing else has open. */
+               if (!dm_tree_deactivate_children(root, dlid, DLID_SIZE))
                        goto_out;
                if (!_remove_lv_symlinks(dm, root))
-                       log_error("Failed to remove all device symlinks associated with %s.", lv->name);
+                       log_warn("Failed to remove all device symlinks associated with %s.", lv->name);
                break;
        case SUSPEND:
                dm_tree_skip_lockfs(root);
-               if (!dm->flush_required && (lv->status & MIRRORED) && !(lv->status & PVMOVE))
+               if (!dm->flush_required && !seg_is_raid(first_seg(lv)) &&
+                   (lv->status & MIRRORED) && !(lv->status & PVMOVE))
                        dm_tree_use_no_flush_suspend(root);
+               /* Fall through */
        case SUSPEND_WITH_LOCKFS:
-               if (!dm_tree_suspend_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1))
+               if (!dm_tree_suspend_children(root, dlid, DLID_SIZE))
                        goto_out;
                break;
        case PRELOAD:
        case ACTIVATE:
                /* Add all required new devices to tree */
-               if (!_add_new_lv_to_dtree(dm, dtree, lv, origin_only ? "real" : NULL))
+               if (!_add_new_lv_to_dtree(dm, dtree, lv, laopts, (lv_is_origin(lv) && laopts->origin_only) ? "real" : NULL))
                        goto_out;
 
                /* Preload any devices required before any suspensions */
-               dm_tree_set_cookie(root, 0);
-               r = dm_tree_preload_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1);
-               if (!dm_udev_wait(dm_tree_get_cookie(root)))
-                       stack;
-               if (!r)
+               if (!dm_tree_preload_children(root, dlid, DLID_SIZE))
                        goto_out;
 
                if (dm_tree_node_size_changed(root))
                        dm->flush_required = 1;
 
                if (action == ACTIVATE) {
-                       dm_tree_set_cookie(root, 0);
-                       r = dm_tree_activate_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1);
-                       if (!dm_udev_wait(dm_tree_get_cookie(root)))
-                               stack;
-                       if (!r)
+                       if (!dm_tree_activate_children(root, dlid, DLID_SIZE))
                                goto_out;
-                       if (!_create_lv_symlinks(dm, root)) {
-                               log_error("Failed to create symlinks for %s.", lv->name);
-                               goto out;
-                       }
+                       if (!_create_lv_symlinks(dm, root))
+                               log_warn("Failed to create symlinks for %s.", lv->name);
                }
 
                break;
@@ -1735,30 +2221,33 @@ static int _tree_action(struct dev_manager *dm, struct logical_volume *lv,
        r = 1;
 
 out:
+       /* Save fs cookie for udev settle, do not wait here */
+       fs_set_cookie(dm_tree_get_cookie(root));
+out_no_root:
        dm_tree_free(dtree);
 
        return r;
 }
 
 /* origin_only may only be set if we are resuming (not activating) an origin LV */
-int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv, unsigned origin_only)
+int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv,
+                        struct lv_activate_opts *laopts)
 {
-       if (!_tree_action(dm, lv, origin_only, ACTIVATE))
+       if (!_tree_action(dm, lv, laopts, ACTIVATE))
                return_0;
 
-       return _tree_action(dm, lv, origin_only, CLEAN);
+       if (!_tree_action(dm, lv, laopts, CLEAN))
+               return_0;
+
+       return 1;
 }
 
 /* origin_only may only be set if we are resuming (not activating) an origin LV */
 int dev_manager_preload(struct dev_manager *dm, struct logical_volume *lv,
-                       unsigned origin_only, int *flush_required)
+                       struct lv_activate_opts *laopts, int *flush_required)
 {
-       /* FIXME Update the pvmove implementation! */
-       if ((lv->status & PVMOVE) || (lv->status & LOCKED))
-               return 1;
-
-       if (!_tree_action(dm, lv, origin_only, PRELOAD))
-               return 0;
+       if (!_tree_action(dm, lv, laopts, PRELOAD))
+               return_0;
 
        *flush_required = dm->flush_required;
 
@@ -1767,19 +2256,23 @@ int dev_manager_preload(struct dev_manager *dm, struct logical_volume *lv,
 
 int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv)
 {
-       int r;
+       struct lv_activate_opts laopts = { 0 };
 
-       r = _tree_action(dm, lv, 0, DEACTIVATE);
+       if (!_tree_action(dm, lv, &laopts, DEACTIVATE))
+               return_0;
 
-       return r;
+       return 1;
 }
 
 int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv,
-                       unsigned origin_only, int lockfs, int flush_required)
+                       struct lv_activate_opts *laopts, int lockfs, int flush_required)
 {
        dm->flush_required = flush_required;
 
-       return _tree_action(dm, lv, origin_only, lockfs ? SUSPEND_WITH_LOCKFS : SUSPEND);
+       if (!_tree_action(dm, lv, laopts, lockfs ? SUSPEND_WITH_LOCKFS : SUSPEND))
+               return_0;
+
+       return 1;
 }
 
 /*
index b0bb275a28d717405031ce70c188199a713ff02c..2d1b7451c4becedb820b934450d7b7aa2beb8c1c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.  
- * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
 #include "metadata-exported.h"
 
 struct logical_volume;
+struct lv_activate_opts;
 struct volume_group;
 struct cmd_context;
 struct dev_manager;
 struct dm_info;
 struct device;
 
+int read_only_lv(struct logical_volume *lv, struct lv_activate_opts *laopts);
+
 /*
  * Constructor and destructor.
  */
 struct dev_manager *dev_manager_create(struct cmd_context *cmd,
-                                      const char *vg_name);
+                                      const char *vg_name,
+                                      unsigned track_pvmove_deps);
 void dev_manager_destroy(struct dev_manager *dm);
 void dev_manager_release(void);
 void dev_manager_exit(void);
@@ -50,11 +54,21 @@ int dev_manager_snapshot_percent(struct dev_manager *dm,
 int dev_manager_mirror_percent(struct dev_manager *dm,
                               const struct logical_volume *lv, int wait,
                               percent_t *percent, uint32_t *event_nr);
+int dev_manager_thin_pool_status(struct dev_manager *dm,
+                                const struct logical_volume *lv,
+                                struct dm_status_thin_pool **status);
+int dev_manager_thin_pool_percent(struct dev_manager *dm,
+                                 const struct logical_volume *lv,
+                                 int metadata, percent_t *percent);
+int dev_manager_thin_percent(struct dev_manager *dm,
+                            const struct logical_volume *lv,
+                            int mapped, percent_t *percent);
 int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv,
-                       unsigned origin_only, int lockfs, int flush_required);
-int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv, unsigned origin_only);
+                       struct lv_activate_opts *laopts, int lockfs, int flush_required);
+int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv,
+                        struct lv_activate_opts *laopts);
 int dev_manager_preload(struct dev_manager *dm, struct logical_volume *lv,
-                       unsigned origin_only, int *flush_required);
+                       struct lv_activate_opts *laopts, int *flush_required);
 int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv);
 int dev_manager_transient(struct dev_manager *dm, struct logical_volume *lv) __attribute__((nonnull(1, 2)));
 
index 1523115ba8f1b924647db71c9dc21f0a8680f45d..2636ccf3db0b8cd72425a8defad29902e0268bd8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -15,6 +15,7 @@
 
 #include "lib.h"
 #include "fs.h"
+#include "activate.h"
 #include "toolcontext.h"
 #include "lvm-string.h"
 #include "lvm-file.h"
 #include <limits.h>
 #include <dirent.h>
 
+/*
+ * Library cookie to combine multiple fs transactions.
+ * Supports to wait for udev device settle only when needed.
+ */
+static uint32_t _fs_cookie = DM_COOKIE_AUTO_CREATE;
+static int _fs_create = 0;
+
 static int _mk_dir(const char *dev_dir, const char *vg_name)
 {
-       char vg_path[PATH_MAX];
+       static char vg_path[PATH_MAX];
        mode_t old_umask;
 
        if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s",
@@ -59,7 +67,7 @@ static int _mk_dir(const char *dev_dir, const char *vg_name)
 
 static int _rm_dir(const char *dev_dir, const char *vg_name)
 {
-       char vg_path[PATH_MAX];
+       static char vg_path[PATH_MAX];
 
        if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s",
                         dev_dir, vg_name) == -1) {
@@ -79,7 +87,7 @@ static int _rm_dir(const char *dev_dir, const char *vg_name)
 static void _rm_blks(const char *dir)
 {
        const char *name;
-       char path[PATH_MAX];
+       static char path[PATH_MAX];
        struct dirent *dirent;
        struct stat buf;
        DIR *d;
@@ -116,8 +124,8 @@ static void _rm_blks(const char *dir)
 static int _mk_link(const char *dev_dir, const char *vg_name,
                    const char *lv_name, const char *dev, int check_udev)
 {
-       char lv_path[PATH_MAX], link_path[PATH_MAX], lvm1_group_path[PATH_MAX];
-       char vg_path[PATH_MAX];
+       static char lv_path[PATH_MAX], link_path[PATH_MAX], lvm1_group_path[PATH_MAX];
+       static char vg_path[PATH_MAX];
        struct stat buf, buf_lp;
 
        if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s",
@@ -218,7 +226,7 @@ static int _rm_link(const char *dev_dir, const char *vg_name,
                    const char *lv_name, int check_udev)
 {
        struct stat buf;
-       char lv_path[PATH_MAX];
+       static char lv_path[PATH_MAX];
 
        if (dm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
                         dev_dir, vg_name, lv_name) == -1) {
@@ -226,9 +234,12 @@ static int _rm_link(const char *dev_dir, const char *vg_name,
                return 0;
        }
 
-       if (lstat(lv_path, &buf) && errno == ENOENT)
-               return 1;
-       else if (dm_udev_get_sync_support() && udev_checking() && check_udev)
+       if (lstat(lv_path, &buf)) {
+               if (errno == ENOENT)
+                       return 1;
+               log_sys_error("lstat", lv_path);
+               return 0;
+       } else if (dm_udev_get_sync_support() && udev_checking() && check_udev)
                log_warn("The link %s should have been removed by udev "
                         "but it is still present. Falling back to "
                         "direct link removal.", lv_path);
@@ -250,7 +261,8 @@ static int _rm_link(const char *dev_dir, const char *vg_name,
 typedef enum {
        FS_ADD,
        FS_DEL,
-       FS_RENAME
+       FS_RENAME,
+       NUM_FS_OPS
 } fs_op_t;
 
 static int _do_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
@@ -276,12 +288,19 @@ static int _do_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
 
                if (!_mk_link(dev_dir, vg_name, lv_name, dev, check_udev))
                        stack;
+       default:
+               ; /* NOTREACHED */
        }
 
        return 1;
 }
 
 static DM_LIST_INIT(_fs_ops);
+/*
+ * Count number of stacked fs_op_t operations to allow to skip dm_list search.
+ * FIXME: handling of FS_RENAME
+ */
+static int _count_fs_ops[NUM_FS_OPS];
 
 struct fs_op_parms {
        struct dm_list list;
@@ -302,15 +321,84 @@ static void _store_str(char **pos, char **ptr, const char *str)
        *pos += strlen(*ptr) + 1;
 }
 
+static void _del_fs_op(struct fs_op_parms *fsp)
+{
+       _count_fs_ops[fsp->type]--;
+       dm_list_del(&fsp->list);
+       dm_free(fsp);
+}
+
+/* Check if there is other the type of fs operation stacked */
+static int _other_fs_ops(fs_op_t type)
+{
+       unsigned i;
+
+       for (i = 0; i < NUM_FS_OPS; i++)
+               if (type != i && _count_fs_ops[i])
+                       return 1;
+       return 0;
+}
+
+/* Check if udev is supposed to create nodes */
+static int _check_udev(int check_udev)
+{
+    return check_udev && dm_udev_get_sync_support() && dm_udev_get_checking();
+}
+
+/* FIXME: duplication of the  code from libdm-common.c */
 static int _stack_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
                        const char *lv_name, const char *dev,
                        const char *old_lv_name, int check_udev)
 {
+       struct dm_list *fsph, *fspht;
        struct fs_op_parms *fsp;
        size_t len = strlen(dev_dir) + strlen(vg_name) + strlen(lv_name) +
            strlen(dev) + strlen(old_lv_name) + 5;
        char *pos;
 
+       if ((type == FS_DEL) && _other_fs_ops(type))
+               /*
+                * Ignore any outstanding operations on the fs_op if deleting it.
+                */
+               dm_list_iterate_safe(fsph, fspht, &_fs_ops) {
+                       fsp = dm_list_item(fsph, struct fs_op_parms);
+                       if (!strcmp(lv_name, fsp->lv_name) &&
+                           !strcmp(vg_name, fsp->vg_name)) {
+                               _del_fs_op(fsp);
+                               if (!_other_fs_ops(type))
+                                       break; /* no other non DEL ops */
+                       }
+               }
+       else if ((type == FS_ADD) && _count_fs_ops[FS_DEL] && _check_udev(check_udev))
+               /*
+                * If udev is running ignore previous DEL operation on added fs_op.
+                * (No other operations for this device then DEL could be stacked here).
+                */
+               dm_list_iterate_safe(fsph, fspht, &_fs_ops) {
+                       fsp = dm_list_item(fsph, struct fs_op_parms);
+                       if ((fsp->type == FS_DEL) &&
+                           !strcmp(lv_name, fsp->lv_name) &&
+                           !strcmp(vg_name, fsp->vg_name)) {
+                               _del_fs_op(fsp);
+                               break; /* no other DEL ops */
+                       }
+               }
+       else if ((type == FS_RENAME) && _check_udev(check_udev))
+               /*
+                * If udev is running ignore any outstanding operations if renaming it.
+                *
+                * Currently RENAME operation happens through 'suspend -> resume'.
+                * On 'resume' device is added with read_ahead settings, so it
+                * safe to remove any stacked ADD, RENAME, READ_AHEAD operation
+                * There cannot be any DEL operation on the renamed device.
+                */
+               dm_list_iterate_safe(fsph, fspht, &_fs_ops) {
+                       fsp = dm_list_item(fsph, struct fs_op_parms);
+                       if (!strcmp(old_lv_name, fsp->lv_name) &&
+                           !strcmp(vg_name, fsp->vg_name))
+                               _del_fs_op(fsp);
+               }
+
        if (!(fsp = dm_malloc(sizeof(*fsp) + len))) {
                log_error("No space to stack fs operation");
                return 0;
@@ -326,6 +414,7 @@ static int _stack_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
        _store_str(&pos, &fsp->dev, dev);
        _store_str(&pos, &fsp->old_lv_name, old_lv_name);
 
+       _count_fs_ops[type]++;
        dm_list_add(&_fs_ops, &fsp->list);
 
        return 1;
@@ -340,16 +429,17 @@ static void _pop_fs_ops(void)
                fsp = dm_list_item(fsph, struct fs_op_parms);
                _do_fs_op(fsp->type, fsp->dev_dir, fsp->vg_name, fsp->lv_name,
                          fsp->dev, fsp->old_lv_name, fsp->check_udev);
-               dm_list_del(&fsp->list);
-               dm_free(fsp);
+               _del_fs_op(fsp);
        }
+
+       _fs_create = 0;
 }
 
 static int _fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
                  const char *lv_name, const char *dev, const char *old_lv_name,
                  int check_udev)
 {
-       if (memlock()) {
+       if (critical_section()) {
                if (!_stack_fs_op(type, dev_dir, vg_name, lv_name, dev,
                                  old_lv_name, check_udev))
                        return_0;
@@ -395,8 +485,33 @@ int fs_rename_lv(struct logical_volume *lv, const char *dev,
 
 void fs_unlock(void)
 {
-       if (!memlock()) {
+       if (!critical_section()) {
+               log_debug("Syncing device names");
+               /* Wait for all processed udev devices */
+               if (!dm_udev_wait(_fs_cookie))
+                       stack;
+               _fs_cookie = DM_COOKIE_AUTO_CREATE; /* Reset cookie */
                dm_lib_release();
                _pop_fs_ops();
        }
 }
+
+uint32_t fs_get_cookie(void)
+{
+       return _fs_cookie;
+}
+
+void fs_set_cookie(uint32_t cookie)
+{
+       _fs_cookie = cookie;
+}
+
+void fs_set_create(void)
+{
+       _fs_create = 1;
+}
+
+int fs_has_non_delete_ops(void)
+{
+       return _fs_create || _other_fs_ops(FS_DEL);
+}
index 28b2c73f59425e7c8ef44c034ec9d670c14eadbe..9e433c8ea32b631154cacc6ab70c1fb7b9d25eb0 100644 (file)
@@ -29,6 +29,10 @@ int fs_del_lv_byname(const char *dev_dir, const char *vg_name,
                     const char *lv_name, int check_udev);
 int fs_rename_lv(struct logical_volume *lv, const char *dev, 
                 const char *old_vgname, const char *old_lvname);
-void fs_unlock(void);
+/* void fs_unlock(void);  moved to activate.h */
+uint32_t fs_get_cookie(void);
+void fs_set_cookie(uint32_t cookie);
+void fs_set_create(void);
+int fs_has_non_delete_ops(void);
 
 #endif
index d545563100a4a6a95e3fb0dbcbe23b877fc8792c..2c431b1ff073b96c380cece912d19c56250b0832 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
 #include "format-text.h"
 #include "format_pool.h"
 #include "format1.h"
+#include "config.h"
+
+#include "lvmetad.h"
+
+#define CACHE_INVALID  0x00000001
+#define CACHE_LOCKED   0x00000002
+
+/* One per device */
+struct lvmcache_info {
+       struct dm_list list;    /* Join VG members together */
+       struct dm_list mdas;    /* list head for metadata areas */
+       struct dm_list das;     /* list head for data areas */
+       struct lvmcache_vginfo *vginfo; /* NULL == unknown */
+       struct label *label;
+       const struct format_type *fmt;
+       struct device *dev;
+       uint64_t device_size;   /* Bytes */
+       uint32_t status;
+};
+
+/* One per VG */
+struct lvmcache_vginfo {
+       struct dm_list list;    /* Join these vginfos together */
+       struct dm_list infos;   /* List head for lvmcache_infos */
+       const struct format_type *fmt;
+       char *vgname;           /* "" == orphan */
+       uint32_t status;
+       char vgid[ID_LEN + 1];
+       char _padding[7];
+       struct lvmcache_vginfo *next; /* Another VG with same name? */
+       char *creation_host;
+       size_t vgmetadata_size;
+       char *vgmetadata;       /* Copy of VG metadata as format_text string */
+       struct dm_config_tree *cft; /* Config tree created from vgmetadata */
+                                   /* Lifetime is directly tied to vgmetadata */
+       struct volume_group *cached_vg;
+       unsigned holders;
+       unsigned vg_use_count;  /* Counter of vg reusage */
+       unsigned precommitted;  /* Is vgmetadata live or precommitted? */
+};
 
 static struct dm_hash_table *_pvid_hash = NULL;
 static struct dm_hash_table *_vgid_hash = NULL;
@@ -72,6 +112,19 @@ int lvmcache_init(void)
        return 1;
 }
 
+void lvmcache_seed_infos_from_lvmetad(struct cmd_context *cmd)
+{
+       if (!lvmetad_active() || _has_scanned)
+               return;
+
+       if (!lvmetad_pv_list_to_lvmcache(cmd)) {
+               stack;
+               return;
+       }
+
+       _has_scanned = 1;
+}
+
 /* Volume Group metadata cache functions */
 static void _free_cached_vgmetadata(struct lvmcache_vginfo *vginfo)
 {
@@ -82,7 +135,15 @@ static void _free_cached_vgmetadata(struct lvmcache_vginfo *vginfo)
 
        vginfo->vgmetadata = NULL;
 
+       /* Release also cached config tree */
+       if (vginfo->cft) {
+               dm_config_destroy(vginfo->cft);
+               vginfo->cft = NULL;
+       }
+
        log_debug("Metadata cache: VG %s wiped.", vginfo->vgname);
+
+       release_vg(vginfo->cached_vg);
 }
 
 /*
@@ -92,21 +153,30 @@ static void _store_metadata(struct volume_group *vg, unsigned precommitted)
 {
        char uuid[64] __attribute__((aligned(8)));
        struct lvmcache_vginfo *vginfo;
-       int size;
+       char *data;
+       size_t size;
 
-       if (!(vginfo = vginfo_from_vgid((const char *)&vg->id))) {
+       if (!(vginfo = lvmcache_vginfo_from_vgid((const char *)&vg->id))) {
                stack;
                return;
        }
 
-       if (vginfo->vgmetadata)
-               _free_cached_vgmetadata(vginfo);
-
-       if (!(size = export_vg_to_buffer(vg, &vginfo->vgmetadata))) {
+       if (!(size = export_vg_to_buffer(vg, &data))) {
                stack;
+               _free_cached_vgmetadata(vginfo);
                return;
        }
 
+       /* Avoid reparsing of the same data string */
+       if (vginfo->vgmetadata && vginfo->vgmetadata_size == size &&
+           strcmp(vginfo->vgmetadata, data) == 0)
+               dm_free(data);
+       else {
+               _free_cached_vgmetadata(vginfo);
+               vginfo->vgmetadata_size = size;
+               vginfo->vgmetadata = data;
+       }
+
        vginfo->precommitted = precommitted;
 
        if (!id_write_format((const struct id *)vginfo->vgid, uuid, sizeof(uuid))) {
@@ -114,7 +184,7 @@ static void _store_metadata(struct volume_group *vg, unsigned precommitted)
                return;
        }
 
-       log_debug("Metadata cache: VG %s (%s) stored (%d bytes%s).",
+       log_debug("Metadata cache: VG %s (%s) stored (%" PRIsize_t " bytes%s).",
                  vginfo->vgname, uuid, size,
                  precommitted ? ", precommitted" : "");
 }
@@ -129,7 +199,7 @@ static void _update_cache_info_lock_state(struct lvmcache_info *info,
         * Cache becomes invalid whenever lock state changes unless
         * exclusive VG_GLOBAL is held (i.e. while scanning).
         */
-       if (!vgname_is_locked(VG_GLOBAL) && (was_locked != locked)) {
+       if (!lvmcache_vgname_is_locked(VG_GLOBAL) && (was_locked != locked)) {
                info->status |= CACHE_INVALID;
                *cached_vgmetadata_valid = 0;
        }
@@ -158,7 +228,7 @@ static void _update_cache_lock_state(const char *vgname, int locked)
 {
        struct lvmcache_vginfo *vginfo;
 
-       if (!(vginfo = vginfo_from_vgname(vgname, NULL)))
+       if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
                return;
 
        _update_cache_vginfo_lock_state(vginfo, locked);
@@ -169,7 +239,7 @@ static void _drop_metadata(const char *vgname, int drop_precommitted)
        struct lvmcache_vginfo *vginfo;
        struct lvmcache_info *info;
 
-       if (!(vginfo = vginfo_from_vgname(vgname, NULL)))
+       if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
                return;
 
        /*
@@ -187,6 +257,10 @@ static void _drop_metadata(const char *vgname, int drop_precommitted)
                        info->status |= CACHE_INVALID;
 
        _free_cached_vgmetadata(vginfo);
+
+       /* VG revert */
+       if (drop_precommitted)
+               vginfo->precommitted = 0;
 }
 
 /*
@@ -198,7 +272,7 @@ void lvmcache_commit_metadata(const char *vgname)
 {
        struct lvmcache_vginfo *vginfo;
 
-       if (!(vginfo = vginfo_from_vgname(vgname, NULL)))
+       if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
                return;
 
        if (vginfo->precommitted) {
@@ -218,7 +292,7 @@ void lvmcache_drop_metadata(const char *vgname, int drop_precommitted)
 
                /* Indicate that PVs could now be missing from the cache */
                init_full_scan_done(0);
-       } else if (!vgname_is_locked(VG_GLOBAL))
+       } else if (!lvmcache_vgname_is_locked(VG_GLOBAL))
                _drop_metadata(vgname, drop_precommitted);
 }
 
@@ -262,13 +336,17 @@ int lvmcache_verify_lock_order(const char *vgname)
                if (!dm_hash_get_data(_lock_hash, n))
                        return_0;
 
-               vgname2 = dm_hash_get_key(_lock_hash, n);
+               if (!(vgname2 = dm_hash_get_key(_lock_hash, n))) {
+                       log_error(INTERNAL_ERROR "VG lock %s hits NULL.",
+                                vgname);
+                       return 0;
+               }
 
                if (!_vgname_order_correct(vgname2, vgname)) {
                        log_errno(EDEADLK, INTERNAL_ERROR "VG lock %s must "
                                  "be requested before %s, not after.",
                                  vgname, vgname2);
-                       return_0;
+                       return 0;
                }
        }
 
@@ -295,7 +373,7 @@ void lvmcache_lock_vgname(const char *vgname, int read_only __attribute__((unuse
                _vgs_locked++;
 }
 
-int vgname_is_locked(const char *vgname)
+int lvmcache_vgname_is_locked(const char *vgname)
 {
        if (!_lock_hash)
                return 0;
@@ -318,7 +396,7 @@ void lvmcache_unlock_vgname(const char *vgname)
                dev_close_all();
 }
 
-int vgs_locked(void)
+int lvmcache_vgs_locked(void)
 {
        return _vgs_locked;
 }
@@ -344,12 +422,12 @@ static void _vginfo_detach_info(struct lvmcache_info *info)
 }
 
 /* If vgid supplied, require a match. */
-struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname, const char *vgid)
+struct lvmcache_vginfo *lvmcache_vginfo_from_vgname(const char *vgname, const char *vgid)
 {
        struct lvmcache_vginfo *vginfo;
 
        if (!vgname)
-               return vginfo_from_vgid(vgid);
+               return lvmcache_vginfo_from_vgid(vgid);
 
        if (!_vgname_hash)
                return NULL;
@@ -366,7 +444,9 @@ struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname, const char *vgid)
        return vginfo;
 }
 
-const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid, unsigned revalidate_labels)
+const struct format_type *lvmcache_fmt_from_vgname(struct cmd_context *cmd,
+                                                  const char *vgname, const char *vgid,
+                                                  unsigned revalidate_labels)
 {
        struct lvmcache_vginfo *vginfo;
        struct lvmcache_info *info;
@@ -374,10 +454,22 @@ const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid,
        struct dm_list *devh, *tmp;
        struct dm_list devs;
        struct device_list *devl;
+       struct volume_group *vg;
+       const struct format_type *fmt;
        char vgid_found[ID_LEN + 1] __attribute__((aligned(8)));
 
-       if (!(vginfo = vginfo_from_vgname(vgname, vgid)))
+       if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid))) {
+               if (!lvmetad_active())
+                       return NULL; /* too bad */
+               /* If we don't have the info but we have lvmetad, we can ask
+                * there before failing. */
+               if ((vg = lvmetad_vg_lookup(cmd, vgname, vgid))) {
+                       fmt = vg->fid->fmt;
+                       release_vg(vg);
+                       return fmt;
+               }
                return NULL;
+       }
 
        /*
         * If this function is called repeatedly, only the first one needs to revalidate.
@@ -403,13 +495,13 @@ const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid,
 
        dm_list_iterate_safe(devh, tmp, &devs) {
                devl = dm_list_item(devh, struct device_list);
-               label_read(devl->dev, &label, UINT64_C(0));
+               (void) label_read(devl->dev, &label, UINT64_C(0));
                dm_list_del(&devl->list);
                dm_free(devl);
        }
 
        /* If vginfo changed, caller needs to rescan */
-       if (!(vginfo = vginfo_from_vgname(vgname, vgid_found)) ||
+       if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid_found)) ||
            strncmp(vginfo->vgid, vgid_found, ID_LEN))
                return NULL;
 
@@ -417,7 +509,7 @@ out:
        return vginfo->fmt;
 }
 
-struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid)
+struct lvmcache_vginfo *lvmcache_vginfo_from_vgid(const char *vgid)
 {
        struct lvmcache_vginfo *vginfo;
        char id[ID_LEN + 1] __attribute__((aligned(8)));
@@ -435,12 +527,12 @@ struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid)
        return vginfo;
 }
 
-const char *vgname_from_vgid(struct dm_pool *mem, const char *vgid)
+const char *lvmcache_vgname_from_vgid(struct dm_pool *mem, const char *vgid)
 {
        struct lvmcache_vginfo *vginfo;
        const char *vgname = NULL;
 
-       if ((vginfo = vginfo_from_vgid(vgid)))
+       if ((vginfo = lvmcache_vginfo_from_vgid(vgid)))
                vgname = vginfo->vgname;
 
        if (mem && vgname)
@@ -461,7 +553,7 @@ static int _info_is_valid(struct lvmcache_info *info)
         * So if the VG appears to be unlocked here, it should be safe
         * to use the cached value.
         */
-       if (info->vginfo && !vgname_is_locked(info->vginfo->vgname))
+       if (info->vginfo && !lvmcache_vgname_is_locked(info->vginfo->vgname))
                return 1;
 
        if (!(info->status & CACHE_LOCKED))
@@ -498,7 +590,7 @@ static int _vginfo_is_invalid(struct lvmcache_vginfo *vginfo)
  * If valid_only is set, data will only be returned if the cached data is
  * known still to be valid.
  */
-struct lvmcache_info *info_from_pvid(const char *pvid, int valid_only)
+struct lvmcache_info *lvmcache_info_from_pvid(const char *pvid, int valid_only)
 {
        struct lvmcache_info *info;
        char id[ID_LEN + 1] __attribute__((aligned(8)));
@@ -518,17 +610,24 @@ struct lvmcache_info *info_from_pvid(const char *pvid, int valid_only)
        return info;
 }
 
+const char *lvmcache_vgname_from_info(struct lvmcache_info *info)
+{
+       if (info->vginfo)
+               return info->vginfo->vgname;
+       return NULL;
+}
+
 char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid)
 {
        struct lvmcache_info *info;
        char *vgname;
 
-       if (!device_from_pvid(cmd, (const struct id *)pvid, NULL)) {
+       if (!lvmcache_device_from_pvid(cmd, (const struct id *)pvid, NULL, NULL)) {
                log_error("Couldn't find device with uuid %s.", pvid);
                return NULL;
        }
 
-       info = info_from_pvid(pvid, 0);
+       info = lvmcache_info_from_pvid(pvid, 0);
        if (!info)
                return_NULL;
 
@@ -544,7 +643,7 @@ static void _rescan_entry(struct lvmcache_info *info)
        struct label *label;
 
        if (info->status & CACHE_INVALID)
-               label_read(info->dev, &label, UINT64_C(0));
+               (void) label_read(info->dev, &label, UINT64_C(0));
 }
 
 static int _scan_invalid(void)
@@ -563,6 +662,9 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
 
        int r = 0;
 
+       if (lvmetad_active())
+               return 1;
+
        /* Avoid recursion when a PVID can't be found! */
        if (_scanning_in_progress)
                return 0;
@@ -579,18 +681,16 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
                goto out;
        }
 
-       if (full_scan == 2 && !cmd->filter->use_count && !refresh_filters(cmd)) {
-               log_error("refresh filters failed");
-               goto out;
-       }
+       if (full_scan == 2 && (cmd->filter && !cmd->filter->use_count) && !refresh_filters(cmd))
+               goto_out;
 
-       if (!(iter = dev_iter_create(cmd->filter, (full_scan == 2) ? 1 : 0))) {
+       if (!cmd->filter || !(iter = dev_iter_create(cmd->filter, (full_scan == 2) ? 1 : 0))) {
                log_error("dev_iter creation failed");
                goto out;
        }
 
        while ((dev = dev_iter_get(iter)))
-               label_read(dev, &label, UINT64_C(0));
+               (void) label_read(dev, &label, UINT64_C(0));
 
        dev_iter_destroy(iter);
 
@@ -617,13 +717,29 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
        return r;
 }
 
-struct volume_group *lvmcache_get_vg(const char *vgid, unsigned precommitted)
+struct volume_group *lvmcache_get_vg(struct cmd_context *cmd, const char *vgname,
+                                    const char *vgid, unsigned precommitted)
 {
        struct lvmcache_vginfo *vginfo;
-       struct volume_group *vg;
+       struct volume_group *vg = NULL;
        struct format_instance *fid;
+       struct format_instance_ctx fic;
+
+       /*
+        * We currently do not store precommitted metadata in lvmetad at
+        * all. This means that any request for precommitted metadata is served
+        * using the classic scanning mechanics, and read from disk or from
+        * lvmcache.
+        */
+       if (lvmetad_active() && !precommitted) {
+               /* Still serve the locally cached VG if available */
+               if (vgid && (vginfo = lvmcache_vginfo_from_vgid(vgid)) &&
+                   vginfo->vgmetadata && (vg = vginfo->cached_vg))
+                       goto out;
+               return lvmetad_vg_lookup(cmd, vgname, vgid);
+       }
 
-       if (!vgid || !(vginfo = vginfo_from_vgid(vgid)) || !vginfo->vgmetadata)
+       if (!vgid || !(vginfo = lvmcache_vginfo_from_vgid(vgid)) || !vginfo->vgmetadata)
                return NULL;
 
        if (!_vginfo_is_valid(vginfo))
@@ -642,32 +758,84 @@ struct volume_group *lvmcache_get_vg(const char *vgid, unsigned precommitted)
         * Note that we do not clear the PRECOMMITTED flag.
         */
        if ((precommitted && !vginfo->precommitted) ||
-           (!precommitted && vginfo->precommitted && !memlock()))
+           (!precommitted && vginfo->precommitted && !critical_section()))
                return NULL;
 
-       if (!(fid = vginfo->fmt->ops->create_instance(vginfo->fmt,
-                                                     vginfo->vgname,
-                                                     vgid, NULL)))
-               return_NULL;
+       /* Use already-cached VG struct when available */
+       if ((vg = vginfo->cached_vg))
+               goto out;
 
-       if (!(vg = import_vg_from_buffer(vginfo->vgmetadata, fid))) {
-               _free_cached_vgmetadata(vginfo);
-               free_vg(vg);
+       fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
+       fic.context.vg_ref.vg_name = vginfo->vgname;
+       fic.context.vg_ref.vg_id = vgid;
+       if (!(fid = vginfo->fmt->ops->create_instance(vginfo->fmt, &fic)))
                return_NULL;
-       }
 
-       log_debug("Using cached %smetadata for VG %s.",
-                 vginfo->precommitted ? "pre-committed" : "", vginfo->vgname);
+       /* Build config tree from vgmetadata, if not yet cached */
+       if (!vginfo->cft &&
+           !(vginfo->cft =
+             dm_config_from_string(vginfo->vgmetadata)))
+               goto_bad;
+
+       if (!(vg = import_vg_from_config_tree(vginfo->cft, fid)))
+               goto_bad;
+
+       /* Cache VG struct for reuse */
+       vginfo->cached_vg = vg;
+       vginfo->holders = 1;
+       vginfo->vg_use_count = 0;
+       vg->vginfo = vginfo;
+
+       if (!dm_pool_lock(vg->vgmem, detect_internal_vg_cache_corruption()))
+               goto_bad;
+
+out:
+       vginfo->holders++;
+       vginfo->vg_use_count++;
+       log_debug("Using cached %smetadata for VG %s with %u holder(s).",
+                 vginfo->precommitted ? "pre-committed " : "",
+                 vginfo->vgname, vginfo->holders);
 
        return vg;
+
+bad:
+       _free_cached_vgmetadata(vginfo);
+       return NULL;
 }
 
+// #if 0
+int lvmcache_vginfo_holders_dec_and_test_for_zero(struct lvmcache_vginfo *vginfo)
+{
+       log_debug("VG %s decrementing %d holder(s) at %p.",
+                 vginfo->cached_vg->name, vginfo->holders, vginfo->cached_vg);
+
+       if (--vginfo->holders)
+               return 0;
+
+       if (vginfo->vg_use_count > 1)
+               log_debug("VG %s reused %d times.",
+                         vginfo->cached_vg->name, vginfo->vg_use_count);
+
+       /* Debug perform crc check only when it's been used more then once */
+       if (!dm_pool_unlock(vginfo->cached_vg->vgmem,
+                           detect_internal_vg_cache_corruption() &&
+                           (vginfo->vg_use_count > 1)))
+               stack;
+
+       vginfo->cached_vg->vginfo = NULL;
+       vginfo->cached_vg = NULL;
+
+       return 1;
+}
+// #endif
+
 struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd,
                                   int include_internal)
 {
        struct dm_list *vgids;
        struct lvmcache_vginfo *vginfo;
 
+       // TODO plug into lvmetad here automagically?
        lvmcache_label_scan(cmd, 0);
 
        if (!(vgids = str_list_create(cmd->mem))) {
@@ -728,7 +896,7 @@ struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname,
                return NULL;
        }
 
-       if (!(vginfo = vginfo_from_vgname(vgname, vgid)))
+       if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid)))
                return pvids;
 
        dm_list_iterate_items(info, &vginfo->infos) {
@@ -742,33 +910,49 @@ struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname,
        return pvids;
 }
 
-struct device *device_from_pvid(struct cmd_context *cmd, const struct id *pvid,
-                               unsigned *scan_done_once)
+static struct device *_device_from_pvid(const struct id *pvid,
+                                       uint64_t *label_sector)
 {
-       struct label *label;
        struct lvmcache_info *info;
+       struct label *label;
+
+       if ((info = lvmcache_info_from_pvid((const char *) pvid, 0))) {
+               if (lvmetad_active()) {
+                       if (info->label && label_sector)
+                               *label_sector = info->label->sector;
+                       return info->dev;
+               }
 
-       /* Already cached ? */
-       if ((info = info_from_pvid((const char *) pvid, 0))) {
                if (label_read(info->dev, &label, UINT64_C(0))) {
                        info = (struct lvmcache_info *) label->info;
-                       if (id_equal(pvid, (struct id *) &info->dev->pvid))
+                       if (id_equal(pvid, (struct id *) &info->dev->pvid)) {
+                               if (label_sector)
+                                       *label_sector = label->sector;
                                return info->dev;
+                        }
                }
        }
+       return NULL;
+}
+
+struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid,
+                               unsigned *scan_done_once, uint64_t *label_sector)
+{
+       struct device *dev;
+
+       /* Already cached ? */
+       dev = _device_from_pvid(pvid, label_sector);
+       if (dev)
+               return dev;
 
        lvmcache_label_scan(cmd, 0);
 
        /* Try again */
-       if ((info = info_from_pvid((const char *) pvid, 0))) {
-               if (label_read(info->dev, &label, UINT64_C(0))) {
-                       info = (struct lvmcache_info *) label->info;
-                       if (id_equal(pvid, (struct id *) &info->dev->pvid))
-                               return info->dev;
-               }
-       }
+       dev = _device_from_pvid(pvid, label_sector);
+       if (dev)
+               return dev;
 
-       if (memlock() || (scan_done_once && *scan_done_once))
+       if (critical_section() || (scan_done_once && *scan_done_once))
                return NULL;
 
        lvmcache_label_scan(cmd, 2);
@@ -776,18 +960,14 @@ struct device *device_from_pvid(struct cmd_context *cmd, const struct id *pvid,
                *scan_done_once = 1;
 
        /* Try again */
-       if ((info = info_from_pvid((const char *) pvid, 0))) {
-               if (label_read(info->dev, &label, UINT64_C(0))) {
-                       info = (struct lvmcache_info *) label->info;
-                       if (id_equal(pvid, (struct id *) &info->dev->pvid))
-                               return info->dev;
-               }
-       }
+       dev = _device_from_pvid(pvid, label_sector);
+       if (dev)
+               return dev;
 
        return NULL;
 }
 
-const char *pvid_from_devname(struct cmd_context *cmd,
+const char *lvmcache_pvid_from_devname(struct cmd_context *cmd,
                              const char *devname)
 {
        struct device *dev;
@@ -813,7 +993,7 @@ static int _free_vginfo(struct lvmcache_vginfo *vginfo)
 
        _free_cached_vgmetadata(vginfo);
 
-       vginfo2 = primary_vginfo = vginfo_from_vgname(vginfo->vgname, NULL);
+       vginfo2 = primary_vginfo = lvmcache_vginfo_from_vgname(vginfo->vgname, NULL);
 
        if (vginfo == primary_vginfo) {
                dm_hash_remove(_vgname_hash, vginfo->vgname);
@@ -823,21 +1003,20 @@ static int _free_vginfo(struct lvmcache_vginfo *vginfo)
                                  vginfo->vgname);
                        r = 0;
                }
-       } else do
-               if (vginfo2->next == vginfo) {
-                       vginfo2->next = vginfo->next;
-                       break;
+       } else
+               while (vginfo2) {
+                       if (vginfo2->next == vginfo) {
+                               vginfo2->next = vginfo->next;
+                               break;
+                       }
+                       vginfo2 = vginfo2->next;
                }
-       while ((vginfo2 = primary_vginfo->next));
 
-       if (vginfo->vgname)
-               dm_free(vginfo->vgname);
-
-       if (vginfo->creation_host)
-               dm_free(vginfo->creation_host);
+       dm_free(vginfo->vgname);
+       dm_free(vginfo->creation_host);
 
        if (*vginfo->vgid && _vgid_hash &&
-           vginfo_from_vgid(vginfo->vgid) == vginfo)
+           lvmcache_vginfo_from_vgid(vginfo->vgid) == vginfo)
                dm_hash_remove(_vgid_hash, vginfo->vgid);
 
        dm_list_del(&vginfo->list);
@@ -886,6 +1065,7 @@ static int _lvmcache_update_pvid(struct lvmcache_info *info, const char *pvid)
        /*
         * Nothing to do if already stored with same pvid.
         */
+
        if (((dm_hash_lookup(_pvid_hash, pvid)) == info) &&
            !strcmp(info->dev->pvid, pvid))
                return 1;
@@ -914,6 +1094,7 @@ static int _lvmcache_update_vgid(struct lvmcache_info *info,
        if (vginfo && *vginfo->vgid)
                dm_hash_remove(_vgid_hash, vginfo->vgid);
        if (!vgid) {
+               /* FIXME: unreachable code path */
                log_debug("lvmcache: %s: clearing VGID", info ? dev_name(info->dev) : vginfo->vgname);
                return 1;
        }
@@ -928,8 +1109,8 @@ static int _lvmcache_update_vgid(struct lvmcache_info *info,
 
        if (!is_orphan_vg(vginfo->vgname))
                log_debug("lvmcache: %s: setting %s VGID to %s",
-                         dev_name(info->dev), vginfo->vgname,
-                         vginfo->vgid);
+                         (info) ? dev_name(info->dev) : "",
+                         vginfo->vgname, vginfo->vgid);
 
        return 1;
 }
@@ -1036,7 +1217,7 @@ static int _lvmcache_update_vgname(struct lvmcache_info *info,
                _drop_vginfo(info, info->vginfo);
 
        /* Get existing vginfo or create new one */
-       if (!(vginfo = vginfo_from_vgname(vgname, vgid))) {
+       if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid))) {
 /*** FIXME - vginfo ends up duplicated instead of renamed.
                // Renaming?  This lookup fails.
                if ((vginfo = vginfo_from_vgid(vgid))) {
@@ -1088,18 +1269,18 @@ static int _lvmcache_update_vgname(struct lvmcache_info *info,
                 * If we're scanning and there's an invalidated entry, remove it.
                 * Otherwise we risk bogus warnings of duplicate VGs.
                 */
-               while ((primary_vginfo = vginfo_from_vgname(vgname, NULL)) &&
-                      _scanning_in_progress && _vginfo_is_invalid(primary_vginfo))
+               while ((primary_vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)) &&
+                      _scanning_in_progress && _vginfo_is_invalid(primary_vginfo)) {
+                       orphan_vginfo = lvmcache_vginfo_from_vgname(primary_vginfo->fmt->orphan_vg_name, NULL);
+                       if (!orphan_vginfo) {
+                               log_error(INTERNAL_ERROR "Orphan vginfo %s lost from cache.",
+                                         primary_vginfo->fmt->orphan_vg_name);
+                               dm_free(vginfo->vgname);
+                               dm_free(vginfo);
+                               return 0;
+                       }
                        dm_list_iterate_items_safe(info2, info3, &primary_vginfo->infos) {
-                               orphan_vginfo = vginfo_from_vgname(primary_vginfo->fmt->orphan_vg_name, NULL);
-                               if (!orphan_vginfo) {
-                                       log_error(INTERNAL_ERROR "Orphan vginfo %s lost from cache.",
-                                                 primary_vginfo->fmt->orphan_vg_name);
-                                       dm_free(vginfo->vgname);
-                                       dm_free(vginfo);
-                                       return 0;
-                               }
-                               _drop_vginfo(info2, primary_vginfo);    
+                               _vginfo_detach_info(info2);
                                _vginfo_attach_info(orphan_vginfo, info2);
                                if (info2->mdas.n)
                                        sprintf(mdabuf, " with %u mdas",
@@ -1111,6 +1292,10 @@ static int _lvmcache_update_vgname(struct lvmcache_info *info,
                                          vgname, orphan_vginfo->vgid[0] ? " (" : "",
                                          orphan_vginfo->vgid[0] ? orphan_vginfo->vgid : "",
                                          orphan_vginfo->vgid[0] ? ")" : "", mdabuf);
+                       }
+
+                       if (!_drop_vginfo(NULL, primary_vginfo))
+                               return_0;
                }
 
                if (!_insert_vginfo(vginfo, vgid, vgstatus, creation_host,
@@ -1134,7 +1319,7 @@ static int _lvmcache_update_vgname(struct lvmcache_info *info,
        else if (!_lvmcache_update_vgid(NULL, vginfo, vgid)) /* Orphans */
                return_0;
 
-       _update_cache_vginfo_lock_state(vginfo, vgname_is_locked(vgname));
+       _update_cache_vginfo_lock_state(vginfo, lvmcache_vgname_is_locked(vgname));
 
        /* FIXME Check consistency of list! */
        vginfo->fmt = fmt;
@@ -1211,10 +1396,14 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
                vgid = vgname;
        }
 
+       /* When using lvmetad, the PV could not have become orphaned. */
+       if (lvmetad_active() && is_orphan_vg(vgname) && info->vginfo)
+               return 1;
+
        /* If PV without mdas is already in a real VG, don't make it orphan */
        if (is_orphan_vg(vgname) && info->vginfo &&
            mdas_empty_or_ignored(&info->mdas) &&
-           !is_orphan_vg(info->vginfo->vgname) && memlock())
+           !is_orphan_vg(info->vginfo->vgname) && critical_section())
                return 1;
 
        /* If moving PV from orphan to real VG, always mark it valid */
@@ -1241,7 +1430,7 @@ int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted)
        dm_list_iterate_items(pvl, &vg->pvs) {
                strncpy(pvid_s, (char *) &pvl->pv->id, sizeof(pvid_s) - 1);
                /* FIXME Could pvl->pv->dev->pvid ever be different? */
-               if ((info = info_from_pvid(pvid_s, 0)) &&
+               if ((info = lvmcache_info_from_pvid(pvid_s, 0)) &&
                    !lvmcache_update_vgname_and_id(info, vg->name,
                                                   (char *) &vg->id,
                                                   vg->status, NULL))
@@ -1269,11 +1458,11 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
                return NULL;
        }
 
-       strncpy(pvid_s, pvid, sizeof(pvid_s));
+       strncpy(pvid_s, pvid, sizeof(pvid_s) - 1);
        pvid_s[sizeof(pvid_s) - 1] = '\0';
 
-       if (!(existing = info_from_pvid(pvid_s, 0)) &&
-           !(existing = info_from_pvid(dev->pvid, 0))) {
+       if (!(existing = lvmcache_info_from_pvid(pvid_s, 0)) &&
+           !(existing = lvmcache_info_from_pvid(dev->pvid, 0))) {
                if (!(label = label_create(labeller)))
                        return_NULL;
                if (!(info = dm_zalloc(sizeof(*info)))) {
@@ -1286,6 +1475,9 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
                info->label = label;
                dm_list_init(&info->list);
                info->dev = dev;
+
+               lvmcache_del_mdas(info);
+               lvmcache_del_das(info);
        } else {
                if (existing->dev != dev) {
                        /* Is the existing entry a duplicate pvid e.g. md ? */
@@ -1440,5 +1632,266 @@ void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans)
        dm_list_init(&_vginfos);
 
        if (retain_orphans)
-               init_lvmcache_orphans(cmd);
+               if (!init_lvmcache_orphans(cmd))
+                       stack;
+}
+
+int lvmcache_pvid_is_locked(const char *pvid) {
+       struct lvmcache_info *info;
+       info = lvmcache_info_from_pvid(pvid, 0);
+       if (!info || !info->vginfo)
+               return 0;
+
+       return lvmcache_vgname_is_locked(info->vginfo->vgname);
+}
+
+int lvmcache_fid_add_mdas(struct lvmcache_info *info, struct format_instance *fid,
+                         const char *id, int id_len)
+{
+       return fid_add_mdas(fid, &info->mdas, id, id_len);
+}
+
+int lvmcache_fid_add_mdas_pv(struct lvmcache_info *info, struct format_instance *fid)
+{
+       return lvmcache_fid_add_mdas(info, fid, info->dev->pvid, ID_LEN);
+}
+
+int lvmcache_fid_add_mdas_vg(struct lvmcache_vginfo *vginfo, struct format_instance *fid)
+{
+       struct lvmcache_info *info;
+       dm_list_iterate_items(info, &vginfo->infos) {
+               if (!lvmcache_fid_add_mdas_pv(info, fid))
+                       return_0;
+       }
+       return 1;
+}
+
+static int _get_pv_if_in_vg(struct lvmcache_info *info,
+                           struct physical_volume *pv)
+{
+       char vgname[NAME_LEN + 1];
+       char vgid[ID_LEN + 1];
+
+       if (info->vginfo && info->vginfo->vgname &&
+           !is_orphan_vg(info->vginfo->vgname)) {
+               /*
+                * get_pv_from_vg_by_id() may call
+                * lvmcache_label_scan() and drop cached
+                * vginfo so make a local copy of string.
+                */
+               strcpy(vgname, info->vginfo->vgname);
+               memcpy(vgid, info->vginfo->vgid, sizeof(vgid));
+
+               if (get_pv_from_vg_by_id(info->fmt, vgname, vgid,
+                                        info->dev->pvid, pv))
+                       return 1;
+       }
+
+       return 0;
+}
+
+int lvmcache_populate_pv_fields(struct lvmcache_info *info,
+                               struct physical_volume *pv,
+                               int scan_label_only)
+{
+       struct data_area_list *da;
+
+       /* Have we already cached vgname? */
+       if (!scan_label_only && _get_pv_if_in_vg(info, pv))
+               return 1;
+
+       /* Perform full scan (just the first time) and try again */
+       if (!scan_label_only && !critical_section() && !full_scan_done()) {
+               lvmcache_label_scan(info->fmt->cmd, 2);
+
+               if (_get_pv_if_in_vg(info, pv))
+                       return 1;
+       }
+
+       /* Orphan */
+       pv->dev = info->dev;
+       pv->fmt = info->fmt;
+       pv->size = info->device_size >> SECTOR_SHIFT;
+       pv->vg_name = FMT_TEXT_ORPHAN_VG_NAME;
+       memcpy(&pv->id, &info->dev->pvid, sizeof(pv->id));
+
+       /* Currently only support exactly one data area */
+       if (dm_list_size(&info->das) != 1) {
+               log_error("Must be exactly one data area (found %d) on PV %s",
+                         dm_list_size(&info->das), dev_name(info->dev));
+               return 0;
+       }
+
+       dm_list_iterate_items(da, &info->das)
+               pv->pe_start = da->disk_locn.offset >> SECTOR_SHIFT;
+
+       return 1;
+}
+
+int lvmcache_check_format(struct lvmcache_info *info, const struct format_type *fmt)
+{
+       if (info->fmt != fmt) {
+               log_error("PV %s is a different format (seqno %s)",
+                         dev_name(info->dev), info->fmt->name);
+               return 0;
+       }
+       return 1;
+}
+
+void lvmcache_del_mdas(struct lvmcache_info *info)
+{
+       if (info->mdas.n)
+               del_mdas(&info->mdas);
+       dm_list_init(&info->mdas);
+}
+
+void lvmcache_del_das(struct lvmcache_info *info)
+{
+       if (info->das.n)
+               del_das(&info->das);
+       dm_list_init(&info->das);
+}
+
+int lvmcache_add_mda(struct lvmcache_info *info, struct device *dev,
+                    uint64_t start, uint64_t size, unsigned ignored)
+{
+       return add_mda(info->fmt, NULL, &info->mdas, dev, start, size, ignored);
+}
+
+int lvmcache_add_da(struct lvmcache_info *info, uint64_t start, uint64_t size)
+{
+       return add_da(NULL, &info->das, start, size);
+}
+
+
+void lvmcache_update_pv(struct lvmcache_info *info, struct physical_volume *pv,
+                       const struct format_type *fmt)
+{
+       info->device_size = pv->size << SECTOR_SHIFT;
+       info->fmt = fmt;
+}
+
+int lvmcache_update_das(struct lvmcache_info *info, struct physical_volume *pv)
+{
+       struct data_area_list *da;
+       if (info->das.n) {
+               if (!pv->pe_start)
+                       dm_list_iterate_items(da, &info->das)
+                               pv->pe_start = da->disk_locn.offset >> SECTOR_SHIFT;
+               del_das(&info->das);
+       } else
+               dm_list_init(&info->das);
+
+       if (!add_da(NULL, &info->das, pv->pe_start << SECTOR_SHIFT, 0 /*pv->size << SECTOR_SHIFT*/))
+               return_0;
+
+       return 1;
+}
+
+int lvmcache_foreach_pv(struct lvmcache_vginfo *vginfo,
+                       int (*fun)(struct lvmcache_info *, void *),
+                       void *baton)
+{
+       struct lvmcache_info *info;
+       dm_list_iterate_items(info, &vginfo->infos) {
+               if (!fun(info, baton))
+                       return_0;
+       }
+
+       return 1;
+}
+
+int lvmcache_foreach_mda(struct lvmcache_info *info,
+                        int (*fun)(struct metadata_area *, void *),
+                        void *baton)
+{
+       struct metadata_area *mda;
+       dm_list_iterate_items(mda, &info->mdas) {
+               if (!fun(mda, baton))
+                       return_0;
+       }
+
+       return 1;
+}
+
+int lvmcache_mda_count(struct lvmcache_info *info)
+{
+       return dm_list_size(&info->mdas);
+}
+
+int lvmcache_foreach_da(struct lvmcache_info *info,
+                       int (*fun)(struct disk_locn *, void *),
+                       void *baton)
+{
+       struct data_area_list *da;
+       dm_list_iterate_items(da, &info->das) {
+               if (!fun(&da->disk_locn, baton))
+                       return_0;
+       }
+
+       return 1;
+}
+
+/*
+ * The lifetime of the label returned is tied to the lifetime of the
+ * lvmcache_info which is the same as lvmcache itself.
+ */
+struct label *lvmcache_get_label(struct lvmcache_info *info) {
+       return info->label;
+}
+
+void lvmcache_make_valid(struct lvmcache_info *info) {
+       info->status &= ~CACHE_INVALID;
+}
+
+uint64_t lvmcache_device_size(struct lvmcache_info *info) {
+       return info->device_size;
+}
+
+void lvmcache_set_device_size(struct lvmcache_info *info, uint64_t size) {
+       info->device_size = size;
+}
+
+struct device *lvmcache_device(struct lvmcache_info *info) {
+       return info->dev;
+}
+
+int lvmcache_is_orphan(struct lvmcache_info *info) {
+       if (!info->vginfo)
+               return 1; /* FIXME? */
+       return is_orphan_vg(info->vginfo->vgname);
+}
+
+int lvmcache_vgid_is_cached(const char *vgid) {
+       struct lvmcache_vginfo *vginfo;
+
+       if (lvmetad_active())
+               return 1;
+
+       vginfo = lvmcache_vginfo_from_vgid(vgid);
+
+       if (!vginfo || !vginfo->vgname)
+               return 0;
+
+       if (is_orphan_vg(vginfo->vgname))
+               return 0;
+
+       return 1;
+}
+
+/*
+ * Return true iff it is impossible to find out from this info alone whether the
+ * PV in question is or is not an orphan.
+ */
+int lvmcache_uncertain_ownership(struct lvmcache_info *info) {
+       return mdas_empty_or_ignored(&info->mdas);
+}
+
+int lvmcache_smallest_mda_size(struct lvmcache_info *info)
+{
+       return find_min_mda_size(&info->mdas);
+}
+
+const struct format_type *lvmcache_fmt(struct lvmcache_info *info) {
+       return info->fmt;
 }
index 06838dc8055061032940750a9d74e5bbeedf2237..615f466575b9bd7dd5c870d55294094d00bcb40e 100644 (file)
 #define ORPHAN_PREFIX VG_ORPHANS
 #define ORPHAN_VG_NAME(fmt) ORPHAN_PREFIX "_" fmt
 
-#define CACHE_INVALID  0x00000001
-#define CACHE_LOCKED   0x00000002
-
 /* LVM specific per-volume info */
 /* Eventual replacement for struct physical_volume perhaps? */
 
 struct cmd_context;
 struct format_type;
 struct volume_group;
+struct physical_volume;
+struct dm_config_tree;
+struct format_instance;
+struct metadata_area;
+struct disk_locn;
 
-/* One per VG */
-struct lvmcache_vginfo {
-       struct dm_list list;    /* Join these vginfos together */
-       struct dm_list infos;   /* List head for lvmcache_infos */
-       const struct format_type *fmt;
-       char *vgname;           /* "" == orphan */
-       uint32_t status;
-       char vgid[ID_LEN + 1];
-       char _padding[7];
-       struct lvmcache_vginfo *next; /* Another VG with same name? */
-       char *creation_host;
-       char *vgmetadata;       /* Copy of VG metadata as format_text string */
-       unsigned precommitted;  /* Is vgmetadata live or precommitted? */
-};
-
-/* One per device */
-struct lvmcache_info {
-       struct dm_list list;    /* Join VG members together */
-       struct dm_list mdas;    /* list head for metadata areas */
-       struct dm_list das;     /* list head for data areas */
-       struct lvmcache_vginfo *vginfo; /* NULL == unknown */
-       struct label *label;
-       const struct format_type *fmt;
-       struct device *dev;
-       uint64_t device_size;   /* Bytes */
-       uint32_t status;
-};
+struct lvmcache_vginfo;
 
 int lvmcache_init(void);
+void lvmcache_allow_reads_with_lvmetad(void);
+
 void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans);
 
 /* Set full_scan to 1 to reread every filtered device label or
@@ -88,19 +66,26 @@ void lvmcache_unlock_vgname(const char *vgname);
 int lvmcache_verify_lock_order(const char *vgname);
 
 /* Queries */
-const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid, unsigned revalidate_labels);
-struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname,
+const struct format_type *lvmcache_fmt_from_vgname(struct cmd_context *cmd, const char *vgname, const char *vgid, unsigned revalidate_labels);
+
+/* Decrement and test if there are still vg holders in vginfo. */
+int lvmcache_vginfo_holders_dec_and_test_for_zero(struct lvmcache_vginfo *vginfo);
+
+struct lvmcache_vginfo *lvmcache_vginfo_from_vgname(const char *vgname,
                                           const char *vgid);
-struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid);
-struct lvmcache_info *info_from_pvid(const char *pvid, int valid_only);
-const char *vgname_from_vgid(struct dm_pool *mem, const char *vgid);
-struct device *device_from_pvid(struct cmd_context *cmd, const struct id *pvid,
-                               unsigned *scan_done_once);
-const char *pvid_from_devname(struct cmd_context *cmd,
+struct lvmcache_vginfo *lvmcache_vginfo_from_vgid(const char *vgid);
+struct lvmcache_info *lvmcache_info_from_pvid(const char *pvid, int valid_only);
+const char *lvmcache_vgname_from_vgid(struct dm_pool *mem, const char *vgid);
+struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid,
+                               unsigned *scan_done_once, uint64_t *label_sector);
+const char *lvmcache_pvid_from_devname(struct cmd_context *cmd,
                              const char *dev_name);
 char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid);
-int vgs_locked(void);
-int vgname_is_locked(const char *vgname);
+const char *lvmcache_vgname_from_info(struct lvmcache_info *info);
+int lvmcache_vgs_locked(void);
+int lvmcache_vgname_is_locked(const char *vgname);
+
+void lvmcache_seed_infos_from_lvmetad(struct cmd_context *cmd);
 
 /* Returns list of struct str_lists containing pool-allocated copy of vgnames */
 /* If include_internal is not set, return only proper vg names. */
@@ -117,8 +102,51 @@ struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname,
                                const char *vgid);
 
 /* Returns cached volume group metadata. */
-struct volume_group *lvmcache_get_vg(const char *vgid, unsigned precommitted);
+struct volume_group *lvmcache_get_vg(struct cmd_context *cmd, const char *vgname,
+                                    const char *vgid, unsigned precommitted);
 void lvmcache_drop_metadata(const char *vgname, int drop_precommitted);
 void lvmcache_commit_metadata(const char *vgname);
 
+int lvmcache_pvid_is_locked(const char *pvid);
+int lvmcache_fid_add_mdas(struct lvmcache_info *info, struct format_instance *fid,
+                         const char *id, int id_len);
+int lvmcache_fid_add_mdas_pv(struct lvmcache_info *info, struct format_instance *fid);
+int lvmcache_fid_add_mdas_vg(struct lvmcache_vginfo *vginfo, struct format_instance *fid);
+int lvmcache_populate_pv_fields(struct lvmcache_info *info,
+                               struct physical_volume *pv,
+                               int scan_label_only);
+int lvmcache_check_format(struct lvmcache_info *info, const struct format_type *fmt);
+void lvmcache_del_mdas(struct lvmcache_info *info);
+void lvmcache_del_das(struct lvmcache_info *info);
+int lvmcache_add_mda(struct lvmcache_info *info, struct device *dev,
+                    uint64_t start, uint64_t size, unsigned ignored);
+int lvmcache_add_da(struct lvmcache_info *info, uint64_t start, uint64_t size);
+
+const struct format_type *lvmcache_fmt(struct lvmcache_info *info);
+struct label *lvmcache_get_label(struct lvmcache_info *info);
+
+void lvmcache_update_pv(struct lvmcache_info *info, struct physical_volume *pv,
+                       const struct format_type *fmt);
+int lvmcache_update_das(struct lvmcache_info *info, struct physical_volume *pv);
+int lvmcache_foreach_mda(struct lvmcache_info *info,
+                        int (*fun)(struct metadata_area *, void *),
+                        void *baton);
+
+int lvmcache_foreach_da(struct lvmcache_info *info,
+                       int (*fun)(struct disk_locn *, void *),
+                       void *baton);
+
+int lvmcache_foreach_pv(struct lvmcache_vginfo *vg,
+                       int (*fun)(struct lvmcache_info *, void *), void * baton);
+
+uint64_t lvmcache_device_size(struct lvmcache_info *info);
+void lvmcache_set_device_size(struct lvmcache_info *info, uint64_t size);
+struct device *lvmcache_device(struct lvmcache_info *info);
+void lvmcache_make_valid(struct lvmcache_info *info);
+int lvmcache_is_orphan(struct lvmcache_info *info);
+int lvmcache_uncertain_ownership(struct lvmcache_info *info);
+int lvmcache_mda_count(struct lvmcache_info *info);
+int lvmcache_vgid_is_cached(const char *vgid);
+int lvmcache_smallest_mda_size(struct lvmcache_info *info);
+
 #endif
diff --git a/lib/cache/lvmetad.c b/lib/cache/lvmetad.c
new file mode 100644 (file)
index 0000000..6a374ac
--- /dev/null
@@ -0,0 +1,915 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "lib.h"
+#include "toolcontext.h"
+#include "metadata.h"
+#include "device.h"
+#include "lvmetad.h"
+#include "lvmcache.h"
+#include "lvmetad-client.h"
+#include "format-text.h" // TODO for disk_locn, used as a DA representation
+#include "assert.h"
+#include "crc.h"
+
+static daemon_handle _lvmetad;
+static int _lvmetad_use = 0;
+static int _lvmetad_connected = 0;
+
+static char *_lvmetad_token = NULL;
+static const char *_lvmetad_socket = NULL;
+static struct cmd_context *_lvmetad_cmd = NULL;
+
+void lvmetad_disconnect(void)
+{
+       daemon_close(_lvmetad);
+       _lvmetad_connected = 0;
+       _lvmetad_cmd = NULL;
+}
+
+void lvmetad_init(struct cmd_context *cmd)
+{
+       if (!_lvmetad_use && !access(LVMETAD_PIDFILE, F_OK))
+               log_warn("WARNING: lvmetad is running but disabled. Restart lvmetad before enabling it!");
+       if (_lvmetad_use && _lvmetad_socket && !_lvmetad_connected) {
+               assert(_lvmetad_socket);
+               _lvmetad = lvmetad_open(_lvmetad_socket);
+               if (_lvmetad.socket_fd >= 0 && !_lvmetad.error) {
+                       _lvmetad_connected = 1;
+                       _lvmetad_cmd = cmd;
+               }
+       }
+}
+
+void lvmetad_warning(void)
+{
+       if (_lvmetad_use && (_lvmetad.socket_fd < 0 || _lvmetad.error))
+               log_warn("WARNING: Failed to connect to lvmetad: %s. Falling back to internal scanning.",
+                        strerror(_lvmetad.error));
+}
+
+int lvmetad_active(void)
+{
+       return _lvmetad_use && _lvmetad_connected;
+}
+
+void lvmetad_set_active(int active)
+{
+       _lvmetad_use = active;
+}
+
+void lvmetad_set_token(const struct dm_config_value *filter)
+{
+       int ft = 0;
+
+       if (_lvmetad_token)
+               dm_free(_lvmetad_token);
+
+       while (filter && filter->type == DM_CFG_STRING) {
+               ft = calc_crc(ft, (const uint8_t *) filter->v.str, strlen(filter->v.str));
+               filter = filter->next;
+       }
+
+       if (!dm_asprintf(&_lvmetad_token, "filter:%u", ft))
+               log_warn("WARNING: Failed to set lvmetad token. Out of memory?");
+}
+
+void lvmetad_release_token(void)
+{
+       dm_free(_lvmetad_token);
+       _lvmetad_token = NULL;
+}
+
+void lvmetad_set_socket(const char *sock)
+{
+       _lvmetad_socket = sock;
+}
+
+static daemon_reply _lvmetad_send(const char *id, ...);
+
+static int _token_update(void)
+{
+       daemon_reply repl = _lvmetad_send("token_update", NULL);
+
+       if (repl.error || strcmp(daemon_reply_str(repl, "response", ""), "OK")) {
+               daemon_reply_destroy(repl);
+               return 0;
+       }
+
+       daemon_reply_destroy(repl);
+       return 1;
+}
+
+
+static daemon_reply _lvmetad_send(const char *id, ...)
+{
+       va_list ap;
+       daemon_reply repl;
+       daemon_request req;
+       int try = 0;
+
+retry:
+       req = daemon_request_make(id);
+
+       if (_lvmetad_token)
+               daemon_request_extend(req, "token = %s", _lvmetad_token, NULL);
+
+       va_start(ap, id);
+       daemon_request_extend_v(req, ap);
+       va_end(ap);
+
+       repl = daemon_send(_lvmetad, req);
+
+       daemon_request_destroy(req);
+
+       if (!repl.error && !strcmp(daemon_reply_str(repl, "response", ""), "token_mismatch") &&
+           try < 2 && !test_mode()) {
+               if (lvmetad_pvscan_all_devs(_lvmetad_cmd, NULL)) {
+                       ++ try;
+                       daemon_reply_destroy(repl);
+                       goto retry;
+               }
+       }
+
+       return repl;
+}
+
+/*
+ * Helper; evaluate the reply from lvmetad, check for errors, print diagnostics
+ * and return a summary success/failure exit code.
+ *
+ * If found is set, *found indicates whether or not device exists,
+ * and missing device is not treated as an error.
+ */
+static int _lvmetad_handle_reply(daemon_reply reply, const char *action, const char *object,
+                                int *found)
+{
+       if (reply.error) {
+               log_error("Request to %s %s%sin lvmetad gave response %s.",
+                         action, object, *object ? " " : "", strerror(reply.error));
+               return 0;
+       }
+
+       /* All OK? */
+       if (!strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
+               if (found)
+                       *found = 1;
+               return 1;
+       }
+
+       /* Unknown device permitted? */
+       if (found && !strcmp(daemon_reply_str(reply, "response", ""), "unknown")) {
+               log_very_verbose("Request to %s %s%sin lvmetad did not find object.",
+                                action, object, *object ? " " : "");
+               *found = 0;
+               return 1;
+       }
+
+       log_error("Request to %s %s%sin lvmetad gave response %s. Reason: %s",
+                 action, object, *object ? " " : "", 
+                 daemon_reply_str(reply, "response", "<missing>"),
+                 daemon_reply_str(reply, "reason", "<missing>"));
+
+       return 0;
+}
+
+static int _read_mda(struct lvmcache_info *info,
+                    struct format_type *fmt,
+                    const struct dm_config_node *cn)
+{
+       struct metadata_area_ops *ops;
+
+       dm_list_iterate_items(ops, &fmt->mda_ops)
+               if (ops->mda_import_text && ops->mda_import_text(info, cn))
+                       return 1;
+
+       return 0;
+}
+
+static struct lvmcache_info *_pv_populate_lvmcache(
+       struct cmd_context *cmd, struct dm_config_node *cn, dev_t fallback)
+{
+       struct device *device;
+       struct id pvid, vgid;
+       char mda_id[32];
+       char da_id[32];
+       int i = 0;
+       struct dm_config_node *mda = NULL;
+       struct dm_config_node *da = NULL;
+       uint64_t offset, size;
+       struct lvmcache_info *info;
+       const char *pvid_txt = dm_config_find_str(cn->child, "id", NULL),
+                  *vgid_txt = dm_config_find_str(cn->child, "vgid", NULL),
+                  *vgname = dm_config_find_str(cn->child, "vgname", NULL),
+                  *fmt_name = dm_config_find_str(cn->child, "format", NULL);
+       dev_t devt = dm_config_find_int(cn->child, "device", 0);
+       uint64_t devsize = dm_config_find_int64(cn->child, "dev_size", 0),
+                label_sector = dm_config_find_int64(cn->child, "label_sector", 0);
+
+       struct format_type *fmt = fmt_name ? get_format_by_name(cmd, fmt_name) : NULL;
+
+       if (!fmt) {
+               log_error("PV %s not recognised. Is the device missing?", pvid_txt);
+               return NULL;
+       }
+
+       device = dev_cache_get_by_devt(devt, cmd->filter);
+       if (!device && fallback)
+               device = dev_cache_get_by_devt(fallback, cmd->filter);
+
+       if (!device) {
+               log_error("No device found for PV %s.", pvid_txt);
+               return NULL;
+       }
+
+       if (!pvid_txt || !id_read_format(&pvid, pvid_txt)) {
+               log_error("Missing or ill-formatted PVID for PV: %s.", pvid_txt);
+               return NULL;
+       }
+
+       if (vgid_txt)
+               id_read_format(&vgid, vgid_txt);
+       else
+               strcpy((char*)&vgid, fmt->orphan_vg_name);
+
+       if (!vgname)
+               vgname = fmt->orphan_vg_name;
+
+       if (!(info = lvmcache_add(fmt->labeller, (const char *)&pvid, device,
+                                 vgname, (const char *)&vgid, 0)))
+               return_NULL;
+
+       lvmcache_get_label(info)->sector = label_sector;
+       lvmcache_set_device_size(info, devsize);
+       lvmcache_del_das(info);
+       lvmcache_del_mdas(info);
+
+       do {
+               sprintf(mda_id, "mda%d", i);
+               mda = dm_config_find_node(cn->child, mda_id);
+               if (mda)
+                       _read_mda(info, fmt, mda);
+               ++i;
+       } while (mda);
+
+       i = 0;
+       do {
+               sprintf(da_id, "da%d", i);
+               da = dm_config_find_node(cn->child, da_id);
+               if (da) {
+                       if (!dm_config_get_uint64(da->child, "offset", &offset)) return_0;
+                       if (!dm_config_get_uint64(da->child, "size", &size)) return_0;
+                       lvmcache_add_da(info, offset, size);
+               }
+               ++i;
+       } while (da);
+
+       return info;
+}
+
+struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgname, const char *vgid)
+{
+       struct volume_group *vg = NULL;
+       daemon_reply reply;
+       char uuid[64];
+       struct format_instance *fid;
+       struct format_instance_ctx fic;
+       struct dm_config_node *top;
+       const char *name;
+       const char *fmt_name;
+       struct format_type *fmt;
+       struct dm_config_node *pvcn;
+       struct pv_list *pvl;
+       struct lvmcache_info *info;
+
+       if (!lvmetad_active())
+               return NULL;
+
+       if (vgid) {
+               if (!id_write_format((const struct id*)vgid, uuid, sizeof(uuid)))
+                       return_NULL;
+               reply = _lvmetad_send("vg_lookup", "uuid = %s", uuid, NULL);
+       } else {
+               if (!vgname)
+                       log_error(INTERNAL_ERROR "VG name required (VGID not available)");
+               reply = _lvmetad_send("vg_lookup", "name = %s", vgname, NULL);
+       }
+
+       if (!reply.error && !strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
+
+               if (!(top = dm_config_find_node(reply.cft->root, "metadata"))) {
+                       log_error(INTERNAL_ERROR "metadata config node not found.");
+                       goto out;
+               }
+
+               name = daemon_reply_str(reply, "name", NULL);
+
+               /* fall back to lvm2 if we don't know better */
+               fmt_name = dm_config_find_str(top, "metadata/format", "lvm2");
+               if (!(fmt = get_format_by_name(cmd, fmt_name))) {
+                       log_error(INTERNAL_ERROR
+                                 "We do not know the format (%s) reported by lvmetad.",
+                                 fmt_name);
+                       goto out;
+               }
+
+               fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
+               fic.context.vg_ref.vg_name = name;
+               fic.context.vg_ref.vg_id = vgid;
+
+               if (!(fid = fmt->ops->create_instance(fmt, &fic)))
+                       goto_out;
+
+               if ((pvcn = dm_config_find_node(top, "metadata/physical_volumes")))
+                       for (pvcn = pvcn->child; pvcn; pvcn = pvcn->sib)
+                               _pv_populate_lvmcache(cmd, pvcn, 0);
+
+               top->key = name;
+               if (!(vg = import_vg_from_config_tree(reply.cft, fid)))
+                       goto_out;
+
+               dm_list_iterate_items(pvl, &vg->pvs) {
+                       if ((info = lvmcache_info_from_pvid((const char *)&pvl->pv->id, 0))) {
+                               pvl->pv->label_sector = lvmcache_get_label(info)->sector;
+                               pvl->pv->dev = lvmcache_device(info);
+                               if (!lvmcache_fid_add_mdas_pv(info, fid)) {
+                                       vg = NULL;
+                                       goto_out;       /* FIXME error path */
+                               }
+                       } /* else probably missing */
+               }
+
+               lvmcache_update_vg(vg, 0);
+       }
+
+out:
+       daemon_reply_destroy(reply);
+
+       return vg;
+}
+
+struct _fixup_baton {
+       int i;
+       int find;
+       int ignore;
+};
+
+static int _fixup_ignored(struct metadata_area *mda, void *baton) {
+       struct _fixup_baton *b = baton;
+       if (b->i == b->find)
+               mda_set_ignored(mda, b->ignore);
+       b->i ++;
+       return 1;
+}
+
+static struct dm_config_tree *_export_vg_to_config_tree(struct volume_group *vg)
+{
+       char *buf = NULL;
+       struct dm_config_tree *vgmeta;
+
+       if (!export_vg_to_buffer(vg, &buf)) {
+               log_error("Could not format VG metadata.");
+               return 0;
+       }
+
+       if (!(vgmeta = dm_config_from_string(buf))) {
+               log_error("Error parsing VG metadata.");
+               dm_free(buf);
+               return 0;
+       }
+
+       dm_free(buf);
+       return vgmeta;
+}
+
+int lvmetad_vg_update(struct volume_group *vg)
+{
+       daemon_reply reply;
+       struct dm_hash_node *n;
+       struct metadata_area *mda;
+       char mda_id[128], *num;
+       struct pv_list *pvl;
+       struct lvmcache_info *info;
+       struct _fixup_baton baton;
+       struct dm_config_tree *vgmeta;
+
+       if (!vg)
+               return 0;
+
+       if (!lvmetad_active() || test_mode())
+               return 1; /* fake it */
+
+       if (!(vgmeta = _export_vg_to_config_tree(vg)))
+               return_0;
+
+       reply = _lvmetad_send("vg_update", "vgname = %s", vg->name,
+                             "metadata = %t", vgmeta, NULL);
+       dm_config_destroy(vgmeta);
+
+       if (!_lvmetad_handle_reply(reply, "update VG", vg->name, NULL)) {
+               daemon_reply_destroy(reply);
+               return 0;
+       }
+
+       daemon_reply_destroy(reply);
+
+       n = (vg->fid && vg->fid->metadata_areas_index) ?
+               dm_hash_get_first(vg->fid->metadata_areas_index) : NULL;
+       while (n) {
+               mda = dm_hash_get_data(vg->fid->metadata_areas_index, n);
+               strcpy(mda_id, dm_hash_get_key(vg->fid->metadata_areas_index, n));
+               if ((num = strchr(mda_id, '_'))) {
+                       *num = 0;
+                       ++num;
+                       if ((info = lvmcache_info_from_pvid(mda_id, 0))) {
+                               memset(&baton, 0, sizeof(baton));
+                               baton.find = atoi(num);
+                               baton.ignore = mda_is_ignored(mda);
+                               lvmcache_foreach_mda(info, _fixup_ignored, &baton);
+                       }
+               }
+               n = dm_hash_get_next(vg->fid->metadata_areas_index, n);
+       }
+
+       dm_list_iterate_items(pvl, &vg->pvs) {
+               /* NB. the PV fmt pointer is sometimes wrong during vgconvert */
+               if (pvl->pv->dev && !lvmetad_pv_found(&pvl->pv->id, pvl->pv->dev,
+                                                     vg->fid ? vg->fid->fmt : pvl->pv->fmt,
+                                                     pvl->pv->label_sector, NULL, NULL))
+                       return 0;
+       }
+
+       return 1;
+}
+
+int lvmetad_vg_remove(struct volume_group *vg)
+{
+       char uuid[64];
+       daemon_reply reply;
+       int result;
+
+       if (!lvmetad_active() || test_mode())
+               return 1; /* just fake it */
+
+       if (!id_write_format(&vg->id, uuid, sizeof(uuid)))
+               return_0;
+
+       reply = _lvmetad_send("vg_remove", "uuid = %s", uuid, NULL);
+       result = _lvmetad_handle_reply(reply, "remove VG", vg->name, NULL);
+
+       daemon_reply_destroy(reply);
+
+       return result;
+}
+
+int lvmetad_pv_lookup(struct cmd_context *cmd, struct id pvid, int *found)
+{
+       char uuid[64];
+       daemon_reply reply;
+       int result = 0;
+       struct dm_config_node *cn;
+
+       if (!lvmetad_active())
+               return_0;
+
+       if (!id_write_format(&pvid, uuid, sizeof(uuid)))
+               return_0;
+
+       reply = _lvmetad_send("pv_lookup", "uuid = %s", uuid, NULL);
+       if (!_lvmetad_handle_reply(reply, "lookup PV", "", found))
+               goto_out;
+
+       if (found && !*found)
+               goto out_success;
+
+       if (!(cn = dm_config_find_node(reply.cft->root, "physical_volume")))
+               goto_out;
+        else if (!_pv_populate_lvmcache(cmd, cn, 0))
+               goto_out;
+
+out_success:
+       result = 1;
+
+out:
+       daemon_reply_destroy(reply);
+
+       return result;
+}
+
+int lvmetad_pv_lookup_by_dev(struct cmd_context *cmd, struct device *dev, int *found)
+{
+       int result = 0;
+       daemon_reply reply;
+       struct dm_config_node *cn;
+
+       if (!lvmetad_active())
+               return_0;
+
+       reply = _lvmetad_send("pv_lookup", "device = %" PRId64, (int64_t) dev->dev, NULL);
+       if (!_lvmetad_handle_reply(reply, "lookup PV", dev_name(dev), found))
+               goto_out;
+
+       if (found && !*found)
+               goto out_success;
+
+       cn = dm_config_find_node(reply.cft->root, "physical_volume");
+       if (!cn || !_pv_populate_lvmcache(cmd, cn, dev->dev))
+               goto_out;
+
+out_success:
+       result = 1;
+
+out:
+       daemon_reply_destroy(reply);
+       return result;
+}
+
+int lvmetad_pv_list_to_lvmcache(struct cmd_context *cmd)
+{
+       daemon_reply reply;
+       struct dm_config_node *cn;
+
+       if (!lvmetad_active())
+               return 1;
+
+       reply = _lvmetad_send("pv_list", NULL);
+       if (!_lvmetad_handle_reply(reply, "list PVs", "", NULL)) {
+               daemon_reply_destroy(reply);
+               return_0;
+       }
+
+       if ((cn = dm_config_find_node(reply.cft->root, "physical_volumes")))
+               for (cn = cn->child; cn; cn = cn->sib)
+                       _pv_populate_lvmcache(cmd, cn, 0);
+
+       daemon_reply_destroy(reply);
+
+       return 1;
+}
+
+int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd)
+{
+       struct volume_group *tmp;
+       struct id vgid;
+       const char *vgid_txt;
+       daemon_reply reply;
+       struct dm_config_node *cn;
+
+       if (!lvmetad_active())
+               return 1;
+
+       reply = _lvmetad_send("vg_list", NULL);
+       if (!_lvmetad_handle_reply(reply, "list VGs", "", NULL)) {
+               daemon_reply_destroy(reply);
+               return_0;
+       }
+
+       if ((cn = dm_config_find_node(reply.cft->root, "volume_groups")))
+               for (cn = cn->child; cn; cn = cn->sib) {
+                       vgid_txt = cn->key;
+                       if (!id_read_format(&vgid, vgid_txt)) {
+                               stack;
+                               continue;
+                       }
+
+                       /* the call to lvmetad_vg_lookup will poke the VG into lvmcache */
+                       tmp = lvmetad_vg_lookup(cmd, NULL, (const char*)&vgid);
+                       release_vg(tmp);
+               }
+
+       daemon_reply_destroy(reply);
+       return 1;
+}
+
+struct _extract_mda_baton {
+       int i;
+       struct dm_config_tree *cft;
+       struct dm_config_node *pre_sib;
+};
+
+static int _extract_mda(struct metadata_area *mda, void *baton)
+{
+       struct _extract_mda_baton *b = baton;
+       struct dm_config_node *cn;
+       char id[32];
+
+       if (!mda->ops->mda_export_text) /* do nothing */
+               return 1;
+
+       dm_snprintf(id, 32, "mda%d", b->i);
+       if (!(cn = make_config_node(b->cft, id, b->cft->root, b->pre_sib)))
+               return 0;
+       if (!mda->ops->mda_export_text(mda, b->cft, cn))
+               return 0;
+
+       b->i ++;
+       b->pre_sib = cn; /* for efficiency */
+
+       return 1;
+}
+
+static int _extract_da(struct disk_locn *da, void *baton)
+{
+       struct _extract_mda_baton *b = baton;
+       struct dm_config_node *cn;
+       char id[32];
+
+       if (!da)
+               return 1;
+
+       dm_snprintf(id, 32, "da%d", b->i);
+       if (!(cn = make_config_node(b->cft, id, b->cft->root, b->pre_sib)))
+               return 0;
+       if (!config_make_nodes(b->cft, cn, NULL,
+                              "offset = %"PRId64, (int64_t) da->offset,
+                              "size = %"PRId64, (int64_t) da->size,
+                              NULL))
+               return 0;
+
+       b->i ++;
+       b->pre_sib = cn; /* for efficiency */
+
+       return 1;
+}
+
+static int _extract_mdas(struct lvmcache_info *info, struct dm_config_tree *cft,
+                        struct dm_config_node *pre_sib)
+{
+       struct _extract_mda_baton baton = { .i = 0, .cft = cft, .pre_sib = NULL };
+
+       if (!lvmcache_foreach_mda(info, &_extract_mda, &baton))
+               return 0;
+       baton.i = 0;
+       if (!lvmcache_foreach_da(info, &_extract_da, &baton))
+               return 0;
+
+       return 1;
+}
+
+int lvmetad_pv_found(const struct id *pvid, struct device *device, const struct format_type *fmt,
+                    uint64_t label_sector, struct volume_group *vg, activation_handler handler)
+{
+       char uuid[64];
+       daemon_reply reply;
+       struct lvmcache_info *info;
+       struct dm_config_tree *pvmeta, *vgmeta;
+       const char *status;
+       int result;
+
+       if (!lvmetad_active() || test_mode())
+               return 1;
+
+       if (!id_write_format(pvid, uuid, sizeof(uuid)))
+                return_0;
+
+       pvmeta = dm_config_create();
+       if (!pvmeta)
+               return_0;
+
+       info = lvmcache_info_from_pvid((const char *)pvid, 0);
+
+       if (!(pvmeta->root = make_config_node(pvmeta, "pv", NULL, NULL))) {
+               dm_config_destroy(pvmeta);
+               return_0;
+       }
+
+       if (!config_make_nodes(pvmeta, pvmeta->root, NULL,
+                              "device = %"PRId64, (int64_t) device->dev,
+                              "dev_size = %"PRId64, (int64_t) (info ? lvmcache_device_size(info) : 0),
+                              "format = %s", fmt->name,
+                              "label_sector = %"PRId64, (int64_t) label_sector,
+                              "id = %s", uuid,
+                              NULL))
+       {
+               dm_config_destroy(pvmeta);
+               return_0;
+       }
+
+       if (info)
+               /* FIXME A more direct route would be much preferable. */
+               _extract_mdas(info, pvmeta, pvmeta->root);
+
+       if (vg) {
+               if (!(vgmeta = _export_vg_to_config_tree(vg))) {
+                       dm_config_destroy(pvmeta);
+                       return_0;
+               }
+
+               reply = _lvmetad_send("pv_found",
+                                     "pvmeta = %t", pvmeta,
+                                     "vgname = %s", vg->name,
+                                     "metadata = %t", vgmeta,
+                                     NULL);
+               dm_config_destroy(vgmeta);
+       } else {
+               if (handler) {
+                       log_error(INTERNAL_ERROR "Handler needs existing VG.");
+                       dm_free(pvmeta);
+                       return 0;
+               }
+               /* There are no MDAs on this PV. */
+               reply = _lvmetad_send("pv_found", "pvmeta = %t", pvmeta, NULL);
+       }
+
+       dm_config_destroy(pvmeta);
+
+       result = _lvmetad_handle_reply(reply, "update PV", uuid, NULL);
+
+       if (vg && result &&
+           (daemon_reply_int(reply, "seqno_after", -1) != vg->seqno ||
+            daemon_reply_int(reply, "seqno_after", -1) != daemon_reply_int(reply, "seqno_before", -1)))
+               log_warn("WARNING: Inconsistent metadata found for VG %s", vg->name);
+
+       if (result && handler) {
+               status = daemon_reply_str(reply, "status", "<missing>");
+               if (!strcmp(status, "partial"))
+                       handler(vg, 1, CHANGE_AAY);
+               else if (!strcmp(status, "complete"))
+                       handler(vg, 0, CHANGE_AAY);
+               else if (!strcmp(status, "orphan"))
+                       ;
+               else
+                       log_error("Request to %s %s in lvmetad gave status %s.",
+                         "update PV", uuid, status);
+       }
+
+       daemon_reply_destroy(reply);
+
+       return result;
+}
+
+int lvmetad_pv_gone(dev_t device, const char *pv_name, activation_handler handler)
+{
+       daemon_reply reply;
+       int result;
+       int found;
+
+       if (!lvmetad_active() || test_mode())
+               return 1;
+
+       /*
+         *  TODO: automatic volume deactivation takes place here *before*
+         *        all cached info is gone - call handler. Also, consider
+         *        integrating existing deactivation script  that deactivates
+         *        the whole stack from top to bottom (not yet upstream).
+         */
+
+       reply = _lvmetad_send("pv_gone", "device = %" PRId64, (int64_t) device, NULL);
+
+       result = _lvmetad_handle_reply(reply, "drop PV", pv_name, &found);
+       /* We don't care whether or not the daemon had the PV cached. */
+
+       daemon_reply_destroy(reply);
+
+       return result;
+}
+
+int lvmetad_pv_gone_by_dev(struct device *dev, activation_handler handler)
+{
+       return lvmetad_pv_gone(dev->dev, dev_name(dev), handler);
+}
+
+/*
+ * The following code implements pvscan --cache.
+ */
+
+struct _lvmetad_pvscan_baton {
+       struct volume_group *vg;
+       struct format_instance *fid;
+};
+
+static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
+{
+       struct _lvmetad_pvscan_baton *b = baton;
+       struct volume_group *this = mda->ops->vg_read(b->fid, "", mda, 1);
+
+       /* FIXME Also ensure contents match etc. */
+       if (!b->vg || this->seqno > b->vg->seqno)
+               b->vg = this;
+       else if (b->vg)
+               release_vg(this);
+
+       return 1;
+}
+
+int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
+                         activation_handler handler)
+{
+       struct label *label;
+       struct lvmcache_info *info;
+       struct _lvmetad_pvscan_baton baton;
+       /* Create a dummy instance. */
+       struct format_instance_ctx fic = { .type = 0 };
+
+       if (!lvmetad_active()) {
+               log_error("Cannot proceed since lvmetad is not active.");
+               return 0;
+       }
+
+       if (!label_read(dev, &label, 0)) {
+               log_print_unless_silent("No PV label found on %s.", dev_name(dev));
+               if (!lvmetad_pv_gone_by_dev(dev, handler))
+                       goto_bad;
+               return 1;
+       }
+
+       info = (struct lvmcache_info *) label->info;
+
+       baton.vg = NULL;
+       baton.fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info),
+                                                            &fic);
+
+       if (!baton.fid)
+               goto_bad;
+
+       lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
+
+       /* LVM1 VGs have no MDAs. */
+       if (!baton.vg && lvmcache_fmt(info) == get_format_by_name(cmd, "lvm1"))
+               baton.vg = ((struct metadata_area *) dm_list_first(&baton.fid->metadata_areas_in_use))->
+                       ops->vg_read(baton.fid, lvmcache_vgname_from_info(info), NULL, 0);
+
+       if (!baton.vg)
+               lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
+
+       /*
+        * NB. If this command failed and we are relying on lvmetad to have an
+        * *exact* image of the system, the lvmetad instance that went out of
+        * sync needs to be killed.
+        */
+       if (!lvmetad_pv_found((const struct id *) &dev->pvid, dev, lvmcache_fmt(info),
+                             label->sector, baton.vg, handler)) {
+               release_vg(baton.vg);
+               goto_bad;
+       }
+
+       release_vg(baton.vg);
+       return 1;
+
+bad:
+       /* FIXME kill lvmetad automatically if we can */
+       log_error("Update of lvmetad failed. This is a serious problem.\n  "
+                 "It is strongly recommended that you restart lvmetad immediately.");
+       return 0;
+}
+
+int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler)
+{
+       struct dev_iter *iter;
+       struct device *dev;
+       daemon_reply reply;
+       int r = 1;
+       char *future_token;
+       int was_silent;
+
+       if (!(iter = dev_iter_create(cmd->lvmetad_filter, 1))) {
+               log_error("dev_iter creation failed");
+               return 0;
+       }
+
+       future_token = _lvmetad_token;
+       _lvmetad_token = (char *) "update in progress";
+       if (!_token_update()) {
+               dev_iter_destroy(iter);
+               _lvmetad_token = future_token;
+               return 0;
+       }
+
+       reply = _lvmetad_send("pv_clear_all", NULL);
+       if (!_lvmetad_handle_reply(reply, "clear status on all PVs", "", NULL))
+               r = 0;
+       daemon_reply_destroy(reply);
+
+       was_silent = silent_mode();
+       init_silent(1);
+
+       while ((dev = dev_iter_get(iter))) {
+               if (!lvmetad_pvscan_single(cmd, dev, handler))
+                       r = 0;
+
+               if (sigint_caught())
+                       break;
+       }
+
+       init_silent(was_silent);
+
+       dev_iter_destroy(iter);
+
+       _lvmetad_token = future_token;
+       if (!_token_update())
+               return 0;
+
+       return r;
+}
+
diff --git a/lib/cache/lvmetad.h b/lib/cache/lvmetad.h
new file mode 100644 (file)
index 0000000..5f0f552
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LVM_METAD_H
+#define _LVM_METAD_H
+
+#include "config-util.h"
+
+struct volume_group;
+struct cmd_context;
+struct dm_config_tree;
+enum activation_change;
+
+typedef int (*activation_handler) (struct volume_group *vg, int partial,
+                                  enum activation_change activate);
+
+#ifdef LVMETAD_SUPPORT
+/*
+ * Initialise the communication with lvmetad. Normally called by
+ * lvmcache_init. Sets up a global handle for our process.
+ */
+void lvmetad_init(struct cmd_context *);
+
+/*
+ * Override the use of lvmetad for retrieving scan results and metadata.
+ */
+void lvmetad_set_active(int);
+
+/*
+ * Configure the socket that lvmetad_init will use to connect to the daemon.
+ */
+void lvmetad_set_socket(const char *);
+
+/*
+ * Check whether lvmetad is active (where active means both that it is running
+ * and that we have a working connection with it).
+ */
+int lvmetad_active(void);
+
+/* Print a warning if lvmetad is enabled but we failed to connect. */
+void lvmetad_warning(void);
+
+/*
+ * Drop connection to lvmetad. A subsequent lvmetad_init() will re-establish
+ * the connection (possibly at a different socket path).
+ */
+void lvmetad_disconnect(void);
+
+/*
+ * Set the "lvmetad validity token" (currently only consists of the lvmetad
+ * filter. See lvm.conf.
+ */
+void lvmetad_set_token(const struct dm_config_value *filter);
+
+/*
+ * Release allocated token.
+ */
+void lvmetad_release_token(void);
+
+/*
+ * Send a new version of VG metadata to lvmetad. This is normally called after
+ * vg_write but before vg_commit. After vg_commit, lvmetad_vg_commit is called
+ * to seal the transaction. The result of lvmetad_vg_update is that the new
+ * metadata is stored tentatively in lvmetad, but it is not used until
+ * lvmetad_vg_commit. The request is validated immediately and lvmetad_vg_commit
+ * only constitutes a pointer update.
+ */
+int lvmetad_vg_update(struct volume_group *vg);
+
+/*
+ * Inform lvmetad that a VG has been removed. This is not entirely safe, but is
+ * only needed during vgremove, which does not wipe PV labels and therefore
+ * cannot mark the PVs as gone.
+ */
+int lvmetad_vg_remove(struct volume_group *vg);
+
+/*
+ * Notify lvmetad that a PV has been found. It is not an error if the PV is
+ * already marked as present in lvmetad. If a non-NULL vg pointer is supplied,
+ * it is taken to represent the metadata read from the MDA(s) present on that
+ * PV. It *is* an error if: the VG is already known to lvmetad, the sequence
+ * number on the cached and on the discovered PV match but the metadata content
+ * does not.
+ */
+int lvmetad_pv_found(const struct id *pvid, struct device *device,
+                    const struct format_type *fmt, uint64_t label_sector,
+                    struct volume_group *vg, activation_handler handler);
+
+/*
+ * Inform the daemon that the device no longer exists.
+ */
+int lvmetad_pv_gone(dev_t devno, const char *pv_name, activation_handler handler);
+int lvmetad_pv_gone_by_dev(struct device *dev, activation_handler handler);
+
+/*
+ * Request a list of all PVs available to lvmetad. If requested, this will also
+ * read labels off all the PVs to populate lvmcache.
+ */
+int lvmetad_pv_list_to_lvmcache(struct cmd_context *cmd);
+
+/*
+ * Lookup an individual PV.
+ * If found is not NULL, it is set according to whether or not the PV is found,
+ * otherwise if the PV is not found an error is returned.
+ */
+int lvmetad_pv_lookup(struct cmd_context *cmd, struct id pvid, int *found);
+int lvmetad_pv_lookup_by_dev(struct cmd_context *cmd, struct device *dev, int *found);
+
+/*
+ * Request a list of all VGs available to lvmetad and use it to fill in
+ * lvmcache..
+ */
+int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd);
+
+/*
+ * Find a VG by its ID or its name in the lvmetad cache. Gives NULL if the VG is
+ * not found.
+ */
+struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd,
+                                      const char *vgname, const char *vgid);
+
+/*
+ * Scan a single device and update lvmetad with the result(s).
+ */
+int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
+                         activation_handler handler);
+
+int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler);
+
+#  else                /* LVMETAD_SUPPORT */
+
+#    define lvmetad_init(cmd)  do { } while (0)
+#    define lvmetad_disconnect()       do { } while (0)
+#    define lvmetad_set_active(a)      do { } while (0)
+#    define lvmetad_set_socket(a)      do { } while (0)
+#    define lvmetad_active()   (0)
+#    define lvmetad_warning()  do { } while (0)
+#    define lvmetad_set_token(a)       do { } while (0)
+#    define lvmetad_release_token()    do { } while (0)
+#    define lvmetad_vg_update(vg)      (1)
+#    define lvmetad_vg_remove(vg)      (1)
+#    define lvmetad_pv_found(pvid, device, fmt, label_sector, vg, handler)     (1)
+#    define lvmetad_pv_gone(devno, pv_name, handler)   (1)
+#    define lvmetad_pv_gone_by_dev(dev, handler)       (1)
+#    define lvmetad_pv_list_to_lvmcache(cmd)   (1)
+#    define lvmetad_pv_lookup(cmd, pvid, found)        (0)
+#    define lvmetad_pv_lookup_by_dev(cmd, dev, found)  (0)
+#    define lvmetad_vg_list_to_lvmcache(cmd)   (1)
+#    define lvmetad_vg_lookup(cmd, vgname, vgid)       (NULL)
+#    define lvmetad_pvscan_single(cmd, dev, handler)   (0)
+#    define lvmetad_pvscan_all_devs(cmd, handler)      (0)
+
+#  endif       /* LVMETAD_SUPPORT */
+
+#endif
index c4da38af6ef27daa860e980f0c2ec30f3b072b75..d72b0c0e68bc9bd131e91b3c267686c6215e8d5b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -22,6 +22,7 @@
 #include "filter.h"
 #include "filter-composite.h"
 #include "filter-md.h"
+#include "filter-mpath.h"
 #include "filter-persistent.h"
 #include "filter-regex.h"
 #include "filter-sysfs.h"
@@ -33,6 +34,7 @@
 #include "str_list.h"
 #include "segtype.h"
 #include "lvmcache.h"
+#include "lvmetad.h"
 #include "dev-cache.h"
 #include "archiver.h"
 
@@ -58,6 +60,8 @@
 #  include <malloc.h>
 #endif
 
+static const size_t linebuffer_size = 4096;
+
 static int _get_env_vars(struct cmd_context *cmd)
 {
        const char *e;
@@ -95,7 +99,7 @@ static void _get_sysfs_dir(struct cmd_context *cmd)
        }
 
        if (!(fp = fopen(proc_mounts, "r"))) {
-               log_sys_error("_get_sysfs_dir: fopen %s", proc_mounts);
+               log_sys_error("_get_sysfs_dir fopen", proc_mounts);
                return;
        }
 
@@ -140,6 +144,15 @@ static void _init_logging(struct cmd_context *cmd)
            find_config_tree_int(cmd, "log/level", DEFAULT_LOGLEVEL);
        init_debug(cmd->default_settings.debug);
 
+       /*
+        * Suppress all non-essential stdout?
+        * -qq can override the default of 0 to 1 later.
+        * Once set to 1, there is no facility to change it back to 0.
+        */
+       cmd->default_settings.silent = silent_mode() ? :
+           find_config_tree_int(cmd, "log/silent", DEFAULT_SILENT);
+       init_silent(cmd->default_settings.silent);
+
        /* Verbose level for tty output */
        cmd->default_settings.verbose =
            find_config_tree_int(cmd, "log/verbose", DEFAULT_VERBOSE);
@@ -151,9 +164,9 @@ static void _init_logging(struct cmd_context *cmd)
        init_abort_on_internal_errors(find_config_tree_int(cmd, "global/abort_on_internal_errors",
                                                           DEFAULT_ABORT_ON_INTERNAL_ERRORS));
 
-       cmd->default_settings.msg_prefix = find_config_tree_str(cmd,
-                                                          "log/prefix",
-                                                          DEFAULT_MSG_PREFIX);
+       cmd->default_settings.msg_prefix =
+               find_config_tree_str_allow_empty(cmd, "log/prefix", DEFAULT_MSG_PREFIX);
+
        init_msg_prefix(cmd->default_settings.msg_prefix);
 
        cmd->default_settings.cmd_name = find_config_tree_int(cmd,
@@ -198,13 +211,32 @@ static void _init_logging(struct cmd_context *cmd)
        reset_lvm_errno(1);
 }
 
+#ifdef UDEV_SYNC_SUPPORT
+/*
+ * Until the DM_UEVENT_GENERATED_FLAG was introduced in kernel patch 
+ * 856a6f1dbd8940e72755af145ebcd806408ecedd
+ * some operations could not be performed by udev, requiring our fallback code.
+ */
+static int _dm_driver_has_stable_udev_support(void)
+{
+       char vsn[80];
+       unsigned maj, min, patchlevel;
+
+       return driver_version(vsn, sizeof(vsn)) &&
+              (sscanf(vsn, "%u.%u.%u", &maj, &min, &patchlevel) == 3) &&
+              (maj == 4 ? min >= 18 : maj > 4);
+}
+#endif
+
 static int _process_config(struct cmd_context *cmd)
 {
        mode_t old_umask;
        const char *read_ahead;
        struct stat st;
-       const struct config_node *cn;
-       const struct config_value *cv;
+       const struct dm_config_node *cn;
+       const struct dm_config_value *cv;
+       int64_t pv_min_kb;
+       const char *lvmetad_socket;
 
        /* umask */
        cmd->default_settings.umask = find_config_tree_int(cmd,
@@ -225,6 +257,9 @@ static int _process_config(struct cmd_context *cmd)
        }
 #ifdef DEVMAPPER_SUPPORT
        dm_set_dev_dir(cmd->dev_dir);
+
+       if (!dm_set_uuid_prefix("LVM-"))
+               return_0;
 #endif
 
        /* proc dir */
@@ -244,6 +279,7 @@ static int _process_config(struct cmd_context *cmd)
        /* FIXME Use global value of sysfs_dir everywhere instead cmd->sysfs_dir. */
        _get_sysfs_dir(cmd);
        set_sysfs_dir_path(cmd->sysfs_dir);
+       dm_set_sysfs_dir(cmd->sysfs_dir);
 
        /* activation? */
        cmd->default_settings.activation = find_config_tree_int(cmd,
@@ -282,6 +318,39 @@ static int _process_config(struct cmd_context *cmd)
                                                                "activation/udev_sync",
                                                                DEFAULT_UDEV_SYNC);
 
+       init_retry_deactivation(find_config_tree_int(cmd, "activation/retry_deactivation",
+                                                       DEFAULT_RETRY_DEACTIVATION));
+
+       init_activation_checks(find_config_tree_int(cmd, "activation/checks",
+                                                     DEFAULT_ACTIVATION_CHECKS));
+
+#ifdef UDEV_SYNC_SUPPORT
+       /*
+        * We need udev rules to be applied, otherwise we would end up with no
+        * nodes and symlinks! However, we can disable the synchronization itself
+        * in runtime and still have only udev to create the nodes and symlinks
+        * without any fallback.
+        */
+       cmd->default_settings.udev_fallback = cmd->default_settings.udev_rules ?
+               find_config_tree_int(cmd, "activation/verify_udev_operations",
+                                    DEFAULT_VERIFY_UDEV_OPERATIONS) : 1;
+
+       /* Do not rely fully on udev if the udev support is known to be incomplete. */
+       if (!cmd->default_settings.udev_fallback && !_dm_driver_has_stable_udev_support()) {
+               log_very_verbose("Kernel driver has incomplete udev support so "
+                                "LVM will check and perform some operations itself.");
+               cmd->default_settings.udev_fallback = 1;
+       }
+
+#else
+       /* We must use old node/symlink creation code if not compiled with udev support at all! */
+       cmd->default_settings.udev_fallback = 1;
+#endif
+
+       cmd->use_linear_target = find_config_tree_int(cmd,
+                                                     "activation/use_linear_target",
+                                                      DEFAULT_USE_LINEAR_TARGET);
+
        cmd->stripe_filler = find_config_tree_str(cmd,
                                                  "activation/missing_stripe_filler",
                                                  DEFAULT_STRIPE_FILLER);
@@ -312,12 +381,41 @@ static int _process_config(struct cmd_context *cmd)
 
        if ((cn = find_config_tree_node(cmd, "activation/mlock_filter")))
                for (cv = cn->v; cv; cv = cv->next) 
-                       if ((cv->type != CFG_STRING) || !cv->v.str[0]) 
+                       if ((cv->type != DM_CFG_STRING) || !cv->v.str[0]) 
                                log_error("Ignoring invalid activation/mlock_filter entry in config file");
 
        cmd->metadata_read_only = find_config_tree_int(cmd, "global/metadata_read_only",
                                                       DEFAULT_METADATA_READ_ONLY);
 
+       pv_min_kb = find_config_tree_int64(cmd, "devices/pv_min_size", DEFAULT_PV_MIN_SIZE_KB);
+       if (pv_min_kb < PV_MIN_SIZE_KB) {
+               log_warn("Ignoring too small pv_min_size %" PRId64 "KB, using default %dKB.",
+                        pv_min_kb, PV_MIN_SIZE_KB);
+               pv_min_kb = PV_MIN_SIZE_KB;
+       }
+       /* LVM stores sizes internally in units of 512-byte sectors. */
+       init_pv_min_size((uint64_t)pv_min_kb * (1024 >> SECTOR_SHIFT));
+
+       init_detect_internal_vg_cache_corruption
+               (find_config_tree_int(cmd, "global/detect_internal_vg_cache_corruption",
+                                     DEFAULT_DETECT_INTERNAL_VG_CACHE_CORRUPTION));
+
+       lvmetad_disconnect();
+
+       lvmetad_socket = getenv("LVM_LVMETAD_SOCKET");
+       if (!lvmetad_socket)
+               lvmetad_socket = DEFAULT_RUN_DIR "/lvmetad.socket";
+
+       /* TODO?
+               lvmetad_socket = find_config_tree_str(cmd, "lvmetad/socket_path",
+                                                     DEFAULT_RUN_DIR "/lvmetad.socket");
+       */
+       lvmetad_set_socket(lvmetad_socket);
+       cn = find_config_tree_node(cmd, "devices/global_filter");
+       lvmetad_set_token(cn ? cn->v : NULL);
+       lvmetad_set_active(find_config_tree_int(cmd, "global/use_lvmetad", 0));
+       lvmetad_init(cmd);
+
        return 1;
 }
 
@@ -333,11 +431,11 @@ static int _set_tag(struct cmd_context *cmd, const char *tag)
        return 1;
 }
 
-static int _check_host_filters(struct cmd_context *cmd, const struct config_node *hn,
+static int _check_host_filters(struct cmd_context *cmd, const struct dm_config_node *hn,
                               int *passes)
 {
-       const struct config_node *cn;
-       const struct config_value *cv;
+       const struct dm_config_node *cn;
+       const struct dm_config_value *cv;
 
        *passes = 1;
 
@@ -346,10 +444,10 @@ static int _check_host_filters(struct cmd_context *cmd, const struct config_node
                        continue;
                if (!strcmp(cn->key, "host_list")) {
                        *passes = 0;
-                       if (cn->v->type == CFG_EMPTY_ARRAY)
+                       if (cn->v->type == DM_CFG_EMPTY_ARRAY)
                                continue;
                        for (cv = cn->v; cv; cv = cv->next) {
-                               if (cv->type != CFG_STRING) {
+                               if (cv->type != DM_CFG_STRING) {
                                        log_error("Invalid hostname string "
                                                  "for tag %s", cn->key);
                                        return 0;
@@ -369,17 +467,17 @@ static int _check_host_filters(struct cmd_context *cmd, const struct config_node
        return 1;
 }
 
-static int _init_tags(struct cmd_context *cmd, struct config_tree *cft)
+static int _init_tags(struct cmd_context *cmd, struct dm_config_tree *cft)
 {
-       const struct config_node *tn, *cn;
+       const struct dm_config_node *tn, *cn;
        const char *tag;
        int passes;
 
-       if (!(tn = find_config_node(cft->root, "tags")) || !tn->child)
+       if (!(tn = dm_config_find_node(cft->root, "tags")) || !tn->child)
                return 1;
 
        /* NB hosttags 0 when already 1 intentionally does not delete the tag */
-       if (!cmd->hosttags && find_config_int(cft->root, "tags/hosttags",
+       if (!cmd->hosttags && dm_config_find_int(cft->root, "tags/hosttags",
                                              DEFAULT_HOSTTAGS)) {
                /* FIXME Strip out invalid chars: only A-Za-z0-9_+.- */
                if (!_set_tag(cmd, cmd->hostname))
@@ -413,7 +511,7 @@ static int _init_tags(struct cmd_context *cmd, struct config_tree *cft)
 
 static int _load_config_file(struct cmd_context *cmd, const char *tag)
 {
-       char config_file[PATH_MAX] = "";
+       static char config_file[PATH_MAX] = "";
        const char *filler = "";
        struct stat info;
        struct config_tree_list *cfl;
@@ -432,7 +530,7 @@ static int _load_config_file(struct cmd_context *cmd, const char *tag)
                return 0;
        }
 
-       if (!(cfl->cft = create_config_tree(config_file, 0))) {
+       if (!(cfl->cft = config_file_open(config_file, 0))) {
                log_error("config_tree allocation failed");
                return 0;
        }
@@ -444,23 +542,24 @@ static int _load_config_file(struct cmd_context *cmd, const char *tag)
                        goto out;
                }
                log_sys_error("stat", config_file);
-               destroy_config_tree(cfl->cft);
+               config_file_destroy(cfl->cft);
                return 0;
        }
 
        log_very_verbose("Loading config file: %s", config_file);
-       if (!read_config_file(cfl->cft)) {
+       if (!config_file_read(cfl->cft)) {
                log_error("Failed to load config file %s", config_file);
-               destroy_config_tree(cfl->cft);
+               config_file_destroy(cfl->cft);
                return 0;
        }
 
        dm_list_add(&cmd->config_files, &cfl->list);
 
       out:
-       if (*tag)
-               _init_tags(cmd, cfl->cft);
-       else
+       if (*tag) {
+               if (!_init_tags(cmd, cfl->cft))
+                       return_0;
+       } else
                /* Use temporary copy of lvm.conf while loading other files */
                cmd->cft = cfl->cft;
 
@@ -472,7 +571,7 @@ static int _init_lvm_conf(struct cmd_context *cmd)
 {
        /* No config file if LVM_SYSTEM_DIR is empty */
        if (!*cmd->system_dir) {
-               if (!(cmd->cft = create_config_tree(NULL, 0))) {
+               if (!(cmd->cft = config_file_open(NULL, 0))) {
                        log_error("Failed to create config tree");
                        return 0;
                }
@@ -499,13 +598,13 @@ static int _init_tag_configs(struct cmd_context *cmd)
        return 1;
 }
 
-static int _merge_config_files(struct cmd_context *cmd)
+static struct dm_config_tree *_merge_config_files(struct cmd_context *cmd, struct dm_config_tree *cft)
 {
        struct config_tree_list *cfl;
 
        /* Replace temporary duplicate copy of lvm.conf */
-       if (cmd->cft->root) {
-               if (!(cmd->cft = create_config_tree(NULL, 0))) {
+       if (cft->root) {
+               if (!(cft = config_file_open(NULL, 0))) {
                        log_error("Failed to create config tree");
                        return 0;
                }
@@ -513,11 +612,11 @@ static int _merge_config_files(struct cmd_context *cmd)
 
        dm_list_iterate_items(cfl, &cmd->config_files) {
                /* Merge all config trees into cmd->cft using merge/tag rules */
-               if (!merge_config_tree(cmd, cmd->cft, cfl->cft))
+               if (!merge_config_tree(cmd, cft, cfl->cft))
                        return_0;
        }
 
-       return 1;
+       return cft;
 }
 
 static void _destroy_tags(struct cmd_context *cmd)
@@ -541,28 +640,43 @@ int config_files_changed(struct cmd_context *cmd)
        return 0;
 }
 
-static void _destroy_tag_configs(struct cmd_context *cmd)
+/*
+ * Returns cmdline config_tree that overrides all others, if present.
+ */
+static struct dm_config_tree *_destroy_tag_configs(struct cmd_context *cmd)
 {
        struct config_tree_list *cfl;
+       struct dm_config_tree *cft_cmdline = NULL, *cft;
+
+       cft = dm_config_remove_cascaded_tree(cmd->cft);
+       if (cft) {
+               cft_cmdline = cmd->cft;
+               cmd->cft = cft;
+       }
 
        dm_list_iterate_items(cfl, &cmd->config_files) {
                if (cfl->cft == cmd->cft)
                        cmd->cft = NULL;
-               destroy_config_tree(cfl->cft);
+               config_file_destroy(cfl->cft);
        }
 
        if (cmd->cft) {
-               destroy_config_tree(cmd->cft);
+               config_file_destroy(cmd->cft);
                cmd->cft = NULL;
        }
 
        dm_list_init(&cmd->config_files);
+
+       return cft_cmdline;
 }
 
 static int _init_dev_cache(struct cmd_context *cmd)
 {
-       const struct config_node *cn;
-       const struct config_value *cv;
+       const struct dm_config_node *cn;
+       const struct dm_config_value *cv;
+       size_t len, udev_dir_len = strlen(DM_UDEV_DEV_DIR);
+       int len_diff;
+       int device_list_from_udev;
 
        init_dev_disable_after_error_count(
                find_config_tree_int(cmd, "devices/disable_after_error_count",
@@ -571,6 +685,11 @@ static int _init_dev_cache(struct cmd_context *cmd)
        if (!dev_cache_init(cmd))
                return_0;
 
+       device_list_from_udev = udev_is_running() ?
+               find_config_tree_bool(cmd, "devices/obtain_device_list_from_udev",
+                                     DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV) : 0;
+       init_obtain_device_list_from_udev(device_list_from_udev);
+
        if (!(cn = find_config_tree_node(cmd, "devices/scan"))) {
                if (!dev_cache_add_dir("/dev")) {
                        log_error("Failed to add /dev to internal "
@@ -583,12 +702,30 @@ static int _init_dev_cache(struct cmd_context *cmd)
        }
 
        for (cv = cn->v; cv; cv = cv->next) {
-               if (cv->type != CFG_STRING) {
+               if (cv->type != DM_CFG_STRING) {
                        log_error("Invalid string in config file: "
                                  "devices/scan");
                        return 0;
                }
 
+               if (device_list_from_udev) {
+                       len = strlen(cv->v.str);
+
+                       /*
+                        * DM_UDEV_DEV_DIR always has '/' at its end.
+                        * If the item in the conf does not have it, be sure
+                        * to make the right comparison without the '/' char!
+                        */
+                       len_diff = len && cv->v.str[len - 1] != '/' ?
+                                       udev_dir_len - 1 != len :
+                                       udev_dir_len != len;
+
+                       if (len_diff || strncmp(DM_UDEV_DEV_DIR, cv->v.str, len)) {
+                               device_list_from_udev = 0;
+                               init_obtain_device_list_from_udev(0);
+                       }
+               }
+
                if (!dev_cache_add_dir(cv->v.str)) {
                        log_error("Failed to add %s to internal device cache",
                                  cv->v.str);
@@ -600,7 +737,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
                return 1;
 
        for (cv = cn->v; cv; cv = cv->next) {
-               if (cv->type != CFG_STRING) {
+               if (cv->type != DM_CFG_STRING) {
                        log_error("Invalid string in config file: "
                                  "devices/loopfiles");
                        return 0;
@@ -617,15 +754,14 @@ static int _init_dev_cache(struct cmd_context *cmd)
        return 1;
 }
 
-#define MAX_FILTERS 4
+#define MAX_FILTERS 5
 
 static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
 {
-       unsigned nr_filt = 0;
-       const struct config_node *cn;
-       struct dev_filter *filters[MAX_FILTERS];
-
-       memset(filters, 0, sizeof(filters));
+       int nr_filt = 0;
+       const struct dm_config_node *cn;
+       struct dev_filter *filters[MAX_FILTERS] = { 0 };
+       struct dev_filter *composite;
 
        /*
         * Filters listed in order: top one gets applied first.
@@ -649,17 +785,19 @@ static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
                log_very_verbose("devices/filter not found in config file: "
                                 "no regex filter installed");
 
-       else if (!(filters[nr_filt++] = regex_filter_create(cn->v))) {
+       else if (!(filters[nr_filt] = regex_filter_create(cn->v))) {
                log_error("Failed to create regex device filter");
-               goto err;
-       }
+               goto bad;
+       } else
+               nr_filt++;
 
        /* device type filter. Required. */
        cn = find_config_tree_node(cmd, "devices/types");
-       if (!(filters[nr_filt++] = lvm_type_filter_create(cmd->proc_dir, cn))) {
+       if (!(filters[nr_filt] = lvm_type_filter_create(cmd->proc_dir, cn))) {
                log_error("Failed to create lvm type filter");
-               goto err;
+               goto bad;
        }
+       nr_filt++;
 
        /* md component filter. Optional, non-critical. */
        if (find_config_tree_bool(cmd, "devices/md_component_detection",
@@ -669,27 +807,40 @@ static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
                        nr_filt++;
        }
 
+       /* mpath component filter. Optional, non-critical. */
+       if (find_config_tree_bool(cmd, "devices/multipath_component_detection",
+                            DEFAULT_MULTIPATH_COMPONENT_DETECTION)) {
+               if ((filters[nr_filt] = mpath_filter_create(cmd->sysfs_dir)))
+                       nr_filt++;
+       }
+
        /* Only build a composite filter if we really need it. */
-       return (nr_filt == 1) ?
-           filters[0] : composite_filter_create(nr_filt, filters);
-err:
-       nr_filt--; /* skip NULL */
-       while (nr_filt-- > 0)
+       if (nr_filt == 1)
+               return filters[0];
+
+       if (!(composite = composite_filter_create(nr_filt, filters)))
+               goto_bad;
+
+       return composite;
+bad:
+       while (--nr_filt >= 0)
                 filters[nr_filt]->destroy(filters[nr_filt]);
+
        return NULL;
 }
 
 static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
 {
+       static char cache_file[PATH_MAX];
        const char *dev_cache = NULL, *cache_dir, *cache_file_prefix;
-       struct dev_filter *f3, *f4;
+       struct dev_filter *f3 = NULL, *f4 = NULL, *toplevel_components[2] = { 0 };
        struct stat st;
-       char cache_file[PATH_MAX];
+       const struct dm_config_node *cn;
 
        cmd->dump_filter = 0;
 
        if (!(f3 = _init_filter_components(cmd)))
-               return 0;
+               goto_bad;
 
        init_ignore_suspended_devices(find_config_tree_int(cmd,
            "devices/ignore_suspended_devices", DEFAULT_IGNORE_SUSPENDED_DEVICES));
@@ -708,7 +859,7 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
                    cache_dir ? : DEFAULT_CACHE_SUBDIR,
                    cache_file_prefix ? : DEFAULT_CACHE_FILE_PREFIX) < 0) {
                        log_error("Persistent cache filename too long.");
-                       return 0;
+                       goto bad;
                }
        } else if (!(dev_cache = find_config_tree_str(cmd, "devices/cache", NULL)) &&
                   (dm_snprintf(cache_file, sizeof(cache_file),
@@ -716,15 +867,16 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
                                cmd->system_dir, DEFAULT_CACHE_SUBDIR,
                                DEFAULT_CACHE_FILE_PREFIX) < 0)) {
                log_error("Persistent cache filename too long.");
-               return 0;
+               goto bad;
        }
 
        if (!dev_cache)
                dev_cache = cache_file;
 
        if (!(f4 = persistent_filter_create(f3, dev_cache))) {
-               log_error("Failed to create persistent device filter");
-               return 0;
+               log_verbose("Failed to create persistent device filter.");
+               f3->destroy(f3);
+               return_0;
        }
 
        /* Should we ever dump persistent filter state? */
@@ -745,9 +897,26 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
                log_verbose("Failed to load existing device cache from %s",
                            dev_cache);
 
-       cmd->filter = f4;
+       if (!(cn = find_config_tree_node(cmd, "devices/global_filter"))) {
+               cmd->filter = f4;
+       } else if (!(cmd->lvmetad_filter = regex_filter_create(cn->v)))
+               goto_bad;
+       else {
+               toplevel_components[0] = cmd->lvmetad_filter;
+               toplevel_components[1] = f4;
+               if (!(cmd->filter = composite_filter_create(2, toplevel_components)))
+                       goto_bad;
+       }
 
        return 1;
+bad:
+       if (f3)
+               f3->destroy(f3);
+       if (f4)
+               f4->destroy(f4);
+       if (toplevel_components[0])
+               toplevel_components[0]->destroy(toplevel_components[0]);
+       return 0;
 }
 
 struct format_type *get_format_by_name(struct cmd_context *cmd, const char *format)
@@ -770,11 +939,9 @@ static int _init_formats(struct cmd_context *cmd)
        struct format_type *fmt;
 
 #ifdef HAVE_LIBDL
-       const struct config_node *cn;
+       const struct dm_config_node *cn;
 #endif
 
-       label_init();
-
 #ifdef LVM1_INTERNAL
        if (!(fmt = init_lvm1_format(cmd)))
                return 0;
@@ -794,12 +961,12 @@ static int _init_formats(struct cmd_context *cmd)
        if (!is_static() &&
            (cn = find_config_tree_node(cmd, "global/format_libraries"))) {
 
-               const struct config_value *cv;
+               const struct dm_config_value *cv;
                struct format_type *(*init_format_fn) (struct cmd_context *);
                void *lib;
 
                for (cv = cn->v; cv; cv = cv->next) {
-                       if (cv->type != CFG_STRING) {
+                       if (cv->type != DM_CFG_STRING) {
                                log_error("Invalid string in config file: "
                                          "global/format_libraries");
                                return 0;
@@ -909,49 +1076,46 @@ static int _init_single_segtype(struct cmd_context *cmd,
 
 static int _init_segtypes(struct cmd_context *cmd)
 {
+       int i;
        struct segment_type *segtype;
-       struct segtype_library seglib = { .cmd = cmd };
+       struct segtype_library seglib = { .cmd = cmd, .lib = NULL };
+       struct segment_type *(*init_segtype_array[])(struct cmd_context *cmd) = {
+               init_striped_segtype,
+               init_zero_segtype,
+               init_error_segtype,
+               init_free_segtype,
+#ifdef SNAPSHOT_INTERNAL
+               init_snapshot_segtype,
+#endif
+#ifdef MIRRORED_INTERNAL
+               init_mirrored_segtype,
+#endif
+               NULL
+       };
 
 #ifdef HAVE_LIBDL
-       const struct config_node *cn;
+       const struct dm_config_node *cn;
 #endif
 
-       if (!(segtype = init_striped_segtype(cmd)))
-               return 0;
-       segtype->library = NULL;
-       dm_list_add(&cmd->segtypes, &segtype->list);
-
-       if (!(segtype = init_zero_segtype(cmd)))
-               return 0;
-       segtype->library = NULL;
-       dm_list_add(&cmd->segtypes, &segtype->list);
-
-       if (!(segtype = init_error_segtype(cmd)))
-               return 0;
-       segtype->library = NULL;
-       dm_list_add(&cmd->segtypes, &segtype->list);
-
-       if (!(segtype = init_free_segtype(cmd)))
-               return 0;
-       segtype->library = NULL;
-       dm_list_add(&cmd->segtypes, &segtype->list);
+       for (i = 0; init_segtype_array[i]; i++) {
+               if (!(segtype = init_segtype_array[i](cmd)))
+                       return 0;
+               segtype->library = NULL;
+               dm_list_add(&cmd->segtypes, &segtype->list);
+       }
 
-#ifdef SNAPSHOT_INTERNAL
-       if (!(segtype = init_snapshot_segtype(cmd)))
+#ifdef REPLICATOR_INTERNAL
+       if (!init_replicator_segtype(cmd, &seglib))
                return 0;
-       segtype->library = NULL;
-       dm_list_add(&cmd->segtypes, &segtype->list);
 #endif
 
-#ifdef MIRRORED_INTERNAL
-       if (!(segtype = init_mirrored_segtype(cmd)))
+#ifdef RAID_INTERNAL
+       if (!init_raid_segtypes(cmd, &seglib))
                return 0;
-       segtype->library = NULL;
-       dm_list_add(&cmd->segtypes, &segtype->list);
 #endif
 
-#ifdef REPLICATOR_INTERNAL
-       if (!init_replicator_segtype(&seglib))
+#ifdef THIN_INTERNAL
+       if (!init_thin_segtypes(cmd, &seglib))
                return 0;
 #endif
 
@@ -960,12 +1124,12 @@ static int _init_segtypes(struct cmd_context *cmd)
        if (!is_static() &&
            (cn = find_config_tree_node(cmd, "global/segment_libraries"))) {
 
-               const struct config_value *cv;
+               const struct dm_config_value *cv;
                int (*init_multiple_segtypes_fn) (struct cmd_context *,
                                                  struct segtype_library *);
 
                for (cv = cn->v; cv; cv = cv->next) {
-                       if (cv->type != CFG_STRING) {
+                       if (cv->type != DM_CFG_STRING) {
                                log_error("Invalid string in config file: "
                                          "global/segment_libraries");
                                return 0;
@@ -1033,8 +1197,8 @@ static int _init_hostname(struct cmd_context *cmd)
 
 static int _init_backup(struct cmd_context *cmd)
 {
+       static char default_dir[PATH_MAX];
        uint32_t days, min;
-       char default_dir[PATH_MAX];
        const char *dir;
 
        if (!cmd->system_dir[0]) {
@@ -1110,14 +1274,47 @@ static void _init_globals(struct cmd_context *cmd)
 {
        init_full_scan_done(0);
        init_mirror_in_sync(0);
+}
 
+/*
+ * Close and reopen stream on file descriptor fd.
+ */
+static int _reopen_stream(FILE *stream, int fd, const char *mode, const char *name, FILE **new_stream)
+{
+       int fd_copy, new_fd;
+
+       if ((fd_copy = dup(fd)) < 0) {
+               log_sys_error("dup", name);
+               return 0;
+       }
+
+       if (fclose(stream))
+               log_sys_error("fclose", name);
+
+       if ((new_fd = dup2(fd_copy, fd)) < 0)
+               log_sys_error("dup2", name);
+       else if (new_fd != fd)
+               log_error("dup2(%d, %d) returned %d", fd_copy, fd, new_fd);
+
+       if (close(fd_copy) < 0)
+               log_sys_error("close", name);
+
+       if (!(*new_stream = fdopen(fd, mode))) {
+               log_sys_error("fdopen", name);
+               return 0;
+       }
+
+       return 1;
 }
 
 /* Entry point */
 struct cmd_context *create_toolcontext(unsigned is_long_lived,
-                                      const char *system_dir)
+                                      const char *system_dir,
+                                      unsigned set_buffering,
+                                      unsigned threaded)
 {
        struct cmd_context *cmd;
+       FILE *new_stream;
 
 #ifdef M_MMAP_MAX
        mallopt(M_MMAP_MAX, 0);
@@ -1137,6 +1334,7 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
                return NULL;
        }
        cmd->is_long_lived = is_long_lived;
+       cmd->threaded = threaded ? 1 : 0;
        cmd->handles_missing_pvs = 0;
        cmd->handles_unknown_segments = 0;
        cmd->independent_metadata_areas = 0;
@@ -1146,10 +1344,46 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
        dm_list_init(&cmd->segtypes);
        dm_list_init(&cmd->tags);
        dm_list_init(&cmd->config_files);
+       label_init();
 
        /* FIXME Make this configurable? */
        reset_lvm_errno(1);
 
+#ifndef VALGRIND_POOL
+       /* Set in/out stream buffering before glibc */
+       if (set_buffering) {
+               /* Allocate 2 buffers */
+               if (!(cmd->linebuffer = dm_malloc(2 * linebuffer_size))) {
+                       log_error("Failed to allocate line buffer.");
+                       goto out;
+               }
+
+               if (is_valid_fd(STDIN_FILENO)) {
+                       if (!_reopen_stream(stdin, STDIN_FILENO, "r", "stdin", &new_stream))
+                               goto_out;
+                       stdin = new_stream;
+                       if (setvbuf(stdin, cmd->linebuffer, _IOLBF, linebuffer_size)) {
+                               log_sys_error("setvbuf", "");
+                               goto out;
+                       }
+               }
+
+               if (is_valid_fd(STDOUT_FILENO)) {
+                       if (!_reopen_stream(stdout, STDOUT_FILENO, "w", "stdout", &new_stream))
+                               goto_out;
+                       stdout = new_stream;
+                       if (setvbuf(stdout, cmd->linebuffer + linebuffer_size,
+                                    _IOLBF, linebuffer_size)) {
+                               log_sys_error("setvbuf", "");
+                               goto out;
+                       }
+               }
+               /* Buffers are used for lines without '\n' */
+       } else
+               /* Without buffering, must not use stdin/stdout */
+               init_silent(1);
+#endif
+
        /*
         * Environment variable LVM_SYSTEM_DIR overrides this below.
         */
@@ -1189,7 +1423,7 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
        if (!_init_tag_configs(cmd))
                goto_out;
 
-       if (!_merge_config_files(cmd))
+       if (!(cmd->cft = _merge_config_files(cmd, cmd->cft)))
                goto_out;
 
        if (!_process_config(cmd))
@@ -1229,6 +1463,11 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
 
        cmd->config_valid = 1;
 out:
+       if (cmd->config_valid != 1) {
+               destroy_toolcontext(cmd);
+               cmd = NULL;
+       }
+
        return cmd;
 }
 
@@ -1289,7 +1528,10 @@ int refresh_filters(struct cmd_context *cmd)
                cmd->filter = NULL;
        }
 
-       r = _init_filters(cmd, 0);
+       cmd->lvmetad_filter = NULL;
+
+       if (!(r = _init_filters(cmd, 0)))
+                stack;
 
        /*
         * During repair code must not reset suspended flag.
@@ -1301,6 +1543,8 @@ int refresh_filters(struct cmd_context *cmd)
 
 int refresh_toolcontext(struct cmd_context *cmd)
 {
+       struct dm_config_tree *cft_cmdline, *cft_tmp;
+
        log_verbose("Reloading config files");
 
        /*
@@ -1319,7 +1563,8 @@ int refresh_toolcontext(struct cmd_context *cmd)
        }
        dev_cache_exit();
        _destroy_tags(cmd);
-       _destroy_tag_configs(cmd);
+
+       cft_cmdline = _destroy_tag_configs(cmd);
 
        cmd->config_valid = 0;
 
@@ -1328,17 +1573,31 @@ int refresh_toolcontext(struct cmd_context *cmd)
        if (!_init_lvm_conf(cmd))
                return 0;
 
+       /* Temporary duplicate cft pointer holding lvm.conf - replaced later */
+       cft_tmp = cmd->cft;
+       if (cft_cmdline)
+               cmd->cft = dm_config_insert_cascaded_tree(cft_cmdline, cft_tmp);
+
+       /* Uses cmd->cft i.e. cft_cmdline + lvm.conf */
        _init_logging(cmd);
 
-       if (!_init_tags(cmd, cmd->cft))
+       /* Init tags from lvm.conf. */
+       if (!_init_tags(cmd, cft_tmp))
                return 0;
 
+       /* Doesn't change cmd->cft */
        if (!_init_tag_configs(cmd))
                return 0;
 
-       if (!_merge_config_files(cmd))
+       /* Merge all the tag config files with lvm.conf, returning a
+        * fresh cft pointer in place of cft_tmp. */
+       if (!(cmd->cft = _merge_config_files(cmd, cft_tmp)))
                return 0;
 
+       /* Finally we can make the proper, fully-merged, cmd->cft */
+       if (cft_cmdline)
+               cmd->cft = dm_config_insert_cascaded_tree(cft_cmdline, cmd->cft);
+
        if (!_process_config(cmd))
                return 0;
 
@@ -1368,6 +1627,9 @@ int refresh_toolcontext(struct cmd_context *cmd)
 
 void destroy_toolcontext(struct cmd_context *cmd)
 {
+       struct dm_config_tree *cft_cmdline;
+       FILE *new_stream;
+
        if (cmd->dump_filter)
                persistent_filter_dump(cmd->filter, 1);
 
@@ -1383,11 +1645,40 @@ void destroy_toolcontext(struct cmd_context *cmd)
                dm_pool_destroy(cmd->mem);
        dev_cache_exit();
        _destroy_tags(cmd);
-       _destroy_tag_configs(cmd);
+
+       if ((cft_cmdline = _destroy_tag_configs(cmd)))
+               dm_config_destroy(cft_cmdline);
        if (cmd->libmem)
                dm_pool_destroy(cmd->libmem);
+
+#ifndef VALGRIND_POOL
+       if (cmd->linebuffer) {
+               /* Reset stream buffering to defaults */
+               if (is_valid_fd(STDIN_FILENO)) {
+                       if (_reopen_stream(stdin, STDIN_FILENO, "r", "stdin", &new_stream)) {
+                               stdin = new_stream;
+                               setlinebuf(stdin);
+                       } else
+                               cmd->linebuffer = NULL; /* Leave buffer in place (deliberate leak) */
+               }
+
+               if (is_valid_fd(STDOUT_FILENO)) {
+                       if (_reopen_stream(stdout, STDOUT_FILENO, "w", "stdout", &new_stream)) {
+                               stdout = new_stream;
+                               setlinebuf(stdout);
+                       } else
+                               cmd->linebuffer = NULL; /* Leave buffer in place (deliberate leak) */
+               }
+
+               dm_free(cmd->linebuffer);
+       }
+#endif
+
        dm_free(cmd);
 
+       lvmetad_release_token();
+       lvmetad_disconnect();
+
        release_log_memory();
        activation_exit();
        reset_log_duplicated();
index 4628c7c2563935ccc007c2b805f4ab5a5a12afb8..6e5803f0e1793bd81646b391f86a8c4e1415a985 100644 (file)
@@ -27,6 +27,7 @@
 struct config_info {
        int debug;
        int verbose;
+       int silent;
        int test;
        int syslog;
        int activation;
@@ -36,6 +37,7 @@ struct config_info {
        int read_ahead;         /* DM_READ_AHEAD_NONE or _AUTO */
        int udev_rules;
        int udev_sync;
+       int udev_fallback;
        int cache_vgmetadata;
        const char *msg_prefix;
        const char *fmt_name;
@@ -46,11 +48,16 @@ struct config_info {
        char _padding[1];
 };
 
-struct config_tree;
+struct dm_config_tree;
 struct archive_params;
 struct backup_params;
 struct arg_values;
 
+struct config_tree_list {
+       struct dm_list list;
+       struct dm_config_tree *cft;
+};
+
 /* FIXME Split into tool & library contexts */
 /* command-instance-related variables needed by library */
 struct cmd_context {
@@ -66,6 +73,7 @@ struct cmd_context {
        const char *kernel_vsn;
 
        unsigned rand_seed;
+       char *linebuffer;
        const char *cmd_line;
        struct command *command;
        char **argv;
@@ -74,19 +82,21 @@ struct cmd_context {
        unsigned is_long_lived:1;       /* Optimises persistent_filter handling */
        unsigned handles_missing_pvs:1;
        unsigned handles_unknown_segments:1;
+       unsigned use_linear_target:1;
        unsigned partial_activation:1;
        unsigned si_unit_consistency:1;
        unsigned metadata_read_only:1;
+       unsigned threaded:1;            /* Set if running within a thread e.g. clvmd */
 
        unsigned independent_metadata_areas:1;  /* Active formats have MDAs outside PVs */
 
        struct dev_filter *filter;
+       struct dev_filter *lvmetad_filter;
        int dump_filter;        /* Dump filter when exiting? */
 
        struct dm_list config_files;
        int config_valid;
-       struct config_tree *cft;
-       struct config_tree *cft_override;
+       struct dm_config_tree *cft;
        struct config_info default_settings;
        struct config_info current_settings;
 
@@ -109,7 +119,9 @@ struct cmd_context {
  * The environment variable LVM_SYSTEM_DIR always takes precedence.
  */
 struct cmd_context *create_toolcontext(unsigned is_long_lived,
-                                      const char *system_dir);
+                                      const char *system_dir,
+                                      unsigned set_buffering,
+                                      unsigned threaded);
 void destroy_toolcontext(struct cmd_context *cmd);
 int refresh_toolcontext(struct cmd_context *cmd);
 int refresh_filters(struct cmd_context *cmd);
index 72908f2a3ede350405087c04f8896b173a9d7716..00bfcab2a9978ff275334c172c7012b09ebaf01d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+
 #include "lib.h"
+
 #include "config.h"
 #include "crc.h"
 #include "device.h"
 #include "str_list.h"
 #include "toolcontext.h"
-#include "lvm-string.h"
 #include "lvm-file.h"
 
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <unistd.h>
 #include <fcntl.h>
-#include <ctype.h>
-
-#define SECTION_B_CHAR '{'
-#define SECTION_E_CHAR '}'
-
-enum {
-       TOK_INT,
-       TOK_FLOAT,
-       TOK_STRING,             /* Single quotes */
-       TOK_STRING_ESCAPED,     /* Double quotes */
-       TOK_EQ,
-       TOK_SECTION_B,
-       TOK_SECTION_E,
-       TOK_ARRAY_B,
-       TOK_ARRAY_E,
-       TOK_IDENTIFIER,
-       TOK_COMMA,
-       TOK_EOF
-};
-
-struct parser {
-       const char *fb, *fe;            /* file limits */
-
-       int t;                  /* token limits and type */
-       const char *tb, *te;
-
-       int fd;                 /* descriptor for file being parsed */
-       int line;               /* line number we are on */
-
-       struct dm_pool *mem;
-};
+#include <assert.h>
 
-struct cs {
-       struct config_tree cft;
-       struct dm_pool *mem;
+struct config_file {
        time_t timestamp;
+       off_t st_size;
        char *filename;
        int exists;
        int keep_open;
        struct device *dev;
 };
 
-struct output_line {
-       FILE *fp;
-       struct dm_pool *mem;
-       putline_fn putline;
-       void *putline_baton;
-};
-
-static void _get_token(struct parser *p, int tok_prev);
-static void _eat_space(struct parser *p);
-static struct config_node *_file(struct parser *p);
-static struct config_node *_section(struct parser *p);
-static struct config_value *_value(struct parser *p);
-static struct config_value *_type(struct parser *p);
-static int _match_aux(struct parser *p, int t);
-static struct config_value *_create_value(struct dm_pool *mem);
-static struct config_node *_create_node(struct dm_pool *mem);
-static char *_dup_tok(struct parser *p);
-
-static const int sep = '/';
-
-#define MAX_INDENT 32
-
-#define match(t) do {\
-   if (!_match_aux(p, (t))) {\
-       log_error("Parse error at byte %" PRIptrdiff_t " (line %d): unexpected token", \
-                 p->tb - p->fb + 1, p->line); \
-      return 0;\
-   } \
-} while(0);
-
-static int _tok_match(const char *str, const char *b, const char *e)
-{
-       while (*str && (b != e)) {
-               if (*str++ != *b++)
-                       return 0;
-       }
-
-       return !(*str || (b != e));
-}
-
 /*
  * public interface
  */
-struct config_tree *create_config_tree(const char *filename, int keep_open)
-{
-       struct cs *c;
-       struct dm_pool *mem = dm_pool_create("config", 10 * 1024);
-
-       if (!mem) {
-               log_error("Failed to allocate config pool.");
-               return 0;
-       }
-
-       if (!(c = dm_pool_zalloc(mem, sizeof(*c)))) {
-               log_error("Failed to allocate config tree.");
-               dm_pool_destroy(mem);
-               return 0;
-       }
-
-       c->mem = mem;
-       c->cft.root = (struct config_node *) NULL;
-       c->timestamp = 0;
-       c->exists = 0;
-       c->keep_open = keep_open;
-       c->dev = 0;
-       if (filename)
-               c->filename = dm_pool_strdup(c->mem, filename);
-       return &c->cft;
-}
-
-void destroy_config_tree(struct config_tree *cft)
-{
-       struct cs *c = (struct cs *) cft;
-
-       if (c->dev)
-               dev_close(c->dev);
-
-       dm_pool_destroy(c->mem);
-}
-
-static int _parse_config_file(struct parser *p, struct config_tree *cft)
-{
-       p->tb = p->te = p->fb;
-       p->line = 1;
-       _get_token(p, TOK_SECTION_E);
-       if (!(cft->root = _file(p)))
-               return_0;
-
-       return 1;
-}
-
-struct config_tree *create_config_tree_from_string(struct cmd_context *cmd __attribute__((unused)),
-                                                  const char *config_settings)
+struct dm_config_tree *config_file_open(const char *filename, int keep_open)
 {
-       struct cs *c;
-       struct config_tree *cft;
-       struct parser *p;
-
-       if (!(cft = create_config_tree(NULL, 0)))
-               return_NULL;
-
-       c = (struct cs *) cft;
-       if (!(p = dm_pool_alloc(c->mem, sizeof(*p)))) {
-               log_error("Failed to allocate config tree parser.");
-               destroy_config_tree(cft);
+       struct dm_config_tree *cft = dm_config_create();
+       struct config_file *cf;
+       if (!cft)
                return NULL;
-       }
 
-       p->mem = c->mem;
-       p->fb = config_settings;
-       p->fe = config_settings + strlen(config_settings);
+       cf = dm_pool_zalloc(cft->mem, sizeof(struct config_file));
+       if (!cf) goto fail;
 
-       if (!_parse_config_file(p, cft)) {
-               destroy_config_tree(cft);
-               return_NULL;
-       }
-
-       return cft;
-}
+       cf->timestamp = 0;
+       cf->exists = 0;
+       cf->keep_open = keep_open;
+       dm_config_set_custom(cft, cf);
 
-int override_config_tree_from_string(struct cmd_context *cmd,
-                                    const char *config_settings)
-{
-       if (!(cmd->cft_override = create_config_tree_from_string(cmd,config_settings))) {
-               log_error("Failed to set overridden configuration entries.");
-               return 1;
+       if (filename &&
+           !(cf->filename = dm_pool_strdup(cft->mem, filename))) {
+               log_error("Failed to duplicate filename.");
+               goto fail;
        }
 
-       return 0;
+       return cft;
+fail:
+       dm_config_destroy(cft);
+       return NULL;
 }
 
-int read_config_fd(struct config_tree *cft, struct device *dev,
-                  off_t offset, size_t size, off_t offset2, size_t size2,
-                  checksum_fn_t checksum_fn, uint32_t checksum)
+/*
+ * Doesn't populate filename if the file is empty.
+ */
+int config_file_check(struct dm_config_tree *cft, const char **filename, struct stat *info)
 {
-       struct cs *c = (struct cs *) cft;
-       struct parser *p;
-       int r = 0;
-       int use_mmap = 1;
-       off_t mmap_offset = 0;
-       char *buf = NULL;
+       struct config_file *cf = dm_config_get_custom(cft);
+       struct stat _info;
 
-       if (!(p = dm_pool_alloc(c->mem, sizeof(*p))))
-               return_0;
-       p->mem = c->mem;
-
-       /* Only use mmap with regular files */
-       if (!(dev->flags & DEV_REGULAR) || size2)
-               use_mmap = 0;
-
-       if (use_mmap) {
-               mmap_offset = offset % lvm_getpagesize();
-               /* memory map the file */
-               p->fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
-                            MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);
-               if (p->fb == (caddr_t) (-1)) {
-                       log_sys_error("mmap", dev_name(dev));
-                       goto out;
-               }
-               p->fb = p->fb + mmap_offset;
-       } else {
-               if (!(buf = dm_malloc(size + size2)))
-                       return_0;
-               if (!dev_read_circular(dev, (uint64_t) offset, size,
-                                      (uint64_t) offset2, size2, buf)) {
-                       goto out;
-               }
-               p->fb = buf;
-       }
-
-       if (checksum_fn && checksum !=
-           (checksum_fn(checksum_fn(INITIAL_CRC, (const uint8_t *)p->fb, size),
-                        (const uint8_t *)(p->fb + size), size2))) {
-               log_error("%s: Checksum error", dev_name(dev));
-               goto out;
-       }
-
-       p->fe = p->fb + size + size2;
-
-       if (!_parse_config_file(p, cft))
-               goto_out;
-
-       r = 1;
+       if (!info)
+               info = &_info;
 
-      out:
-       if (!use_mmap)
-               dm_free(buf);
-       else {
-               /* unmap the file */
-               if (munmap((char *) (p->fb - mmap_offset), size + mmap_offset)) {
-                       log_sys_error("munmap", dev_name(dev));
-                       r = 0;
-               }
-       }
-
-       return r;
-}
-
-int read_config_file(struct config_tree *cft)
-{
-       struct cs *c = (struct cs *) cft;
-       struct stat info;
-       int r = 1;
-
-       if (stat(c->filename, &info)) {
-               log_sys_error("stat", c->filename);
-               c->exists = 0;
+       if (stat(cf->filename, info)) {
+               log_sys_error("stat", cf->filename);
+               cf->exists = 0;
                return 0;
        }
 
-       if (!S_ISREG(info.st_mode)) {
-               log_error("%s is not a regular file", c->filename);
-               c->exists = 0;
+       if (!S_ISREG(info->st_mode)) {
+               log_error("%s is not a regular file", cf->filename);
+               cf->exists = 0;
                return 0;
        }
 
-       c->exists = 1;
-
-       if (info.st_size == 0) {
-               log_verbose("%s is empty", c->filename);
-               return 1;
-       }
-
-       if (!c->dev) {
-               if (!(c->dev = dev_create_file(c->filename, NULL, NULL, 1)))
-                       return_0;
+       cf->exists = 1;
+       cf->timestamp = info->st_ctime;
+       cf->st_size = info->st_size;
 
-               if (!dev_open_flags(c->dev, O_RDONLY, 0, 0)) {
-                       c->dev = 0;
-                       return_0;
-               }
-       }
-
-       r = read_config_fd(cft, c->dev, 0, (size_t) info.st_size, 0, 0,
-                          (checksum_fn_t) NULL, 0);
-
-       if (!c->keep_open) {
-               dev_close(c->dev);
-               c->dev = 0;
-       }
+       if (info->st_size == 0)
+               log_verbose("%s is empty", cf->filename);
+       else if (filename)
+               *filename = cf->filename;
 
-       c->timestamp = info.st_ctime;
-
-       return r;
-}
-
-time_t config_file_timestamp(struct config_tree *cft)
-{
-       struct cs *c = (struct cs *) cft;
-
-       return c->timestamp;
+       return 1;
 }
 
 /*
  * Return 1 if config files ought to be reloaded
  */
-int config_file_changed(struct config_tree *cft)
+int config_file_changed(struct dm_config_tree *cft)
 {
-       struct cs *c = (struct cs *) cft;
+       struct config_file *cf = dm_config_get_custom(cft);
        struct stat info;
 
-       if (!c->filename)
+       if (!cf->filename)
                return 0;
 
-       if (stat(c->filename, &info) == -1) {
+       if (stat(cf->filename, &info) == -1) {
                /* Ignore a deleted config file: still use original data */
                if (errno == ENOENT) {
-                       if (!c->exists)
+                       if (!cf->exists)
                                return 0;
                        log_very_verbose("Config file %s has disappeared!",
-                                        c->filename);
+                                        cf->filename);
                        goto reload;
                }
-               log_sys_error("stat", c->filename);
+               log_sys_error("stat", cf->filename);
                log_error("Failed to reload configuration files");
                return 0;
        }
 
        if (!S_ISREG(info.st_mode)) {
                log_error("Configuration file %s is not a regular file",
-                         c->filename);
+                         cf->filename);
                goto reload;
        }
 
        /* Unchanged? */
-       if (c->timestamp == info.st_ctime)
+       if (cf->timestamp == info.st_ctime && cf->st_size == info.st_size)
                return 0;
 
       reload:
-       log_verbose("Detected config file change to %s", c->filename);
+       log_verbose("Detected config file change to %s", cf->filename);
        return 1;
 }
 
-static int _line_start(struct output_line *outline)
+void config_file_destroy(struct dm_config_tree *cft)
 {
-       if (!dm_pool_begin_object(outline->mem, 128)) {
-               log_error("dm_pool_begin_object failed for config line");
-               return 0;
-       }
+       struct config_file *cf = dm_config_get_custom(cft);
 
-       return 1;
+       if (cf && cf->dev)
+               if (!dev_close(cf->dev))
+                       stack;
+
+       dm_config_destroy(cft);
 }
 
-static int _line_append(struct output_line *outline, const char *fmt, ...)
-  __attribute__ ((format(printf, 2, 3)));
-static int _line_append(struct output_line *outline, const char *fmt, ...)
+/*
+ * Returns config tree if it was removed.
+ */
+struct dm_config_tree *remove_overridden_config_tree(struct cmd_context *cmd)
 {
-       char buf[4096];
-       va_list ap;
-       int n;
-
-       va_start(ap, fmt);
-       n = vsnprintf(&buf[0], sizeof buf - 1, fmt, ap);
-       va_end(ap);
+       struct dm_config_tree *old_cft = cmd->cft;
+       struct dm_config_tree *cft = dm_config_remove_cascaded_tree(cmd->cft);
 
-       if (n < 0 || n > (int) sizeof buf - 1) {
-               log_error("vsnprintf failed for config line");
-               return 0;
-       }
+       if (!cft)
+               return NULL;
 
-       if (!dm_pool_grow_object(outline->mem, &buf[0], strlen(buf))) {
-               log_error("dm_pool_grow_object failed for config line");
-               return 0;
-       }
+       cmd->cft = cft;
 
-       return 1;
+       return old_cft;
 }
 
-#define line_append(args...) do {if (!_line_append(outline, args)) {return_0;}} while (0)
-
-static int _line_end(struct output_line *outline)
+int override_config_tree_from_string(struct cmd_context *cmd,
+                                    const char *config_settings)
 {
-       const char *line;
+       struct dm_config_tree *cft_new;
 
-       if (!dm_pool_grow_object(outline->mem, "\0", 1)) {
-               log_error("dm_pool_grow_object failed for config line");
-               return 0;
+       if (!(cft_new = dm_config_from_string(config_settings))) {
+               log_error("Failed to set overridden configuration entries.");
+               return 1;
        }
 
-       line = dm_pool_end_object(outline->mem);
-       if (outline->putline)
-               outline->putline(line, outline->putline_baton);
-       else {
-               if (!outline->fp)
-                       log_print("%s", line);
-               else
-                       fprintf(outline->fp, "%s\n", line);
-       }
+       cmd->cft = dm_config_insert_cascaded_tree(cft_new, cmd->cft);
 
-       return 1;
+       return 0;
 }
 
-static int _write_value(struct output_line *outline, const struct config_value *v)
+int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
+                       off_t offset, size_t size, off_t offset2, size_t size2,
+                       checksum_fn_t checksum_fn, uint32_t checksum)
 {
-       char *buf;
+       char *fb, *fe;
+       int r = 0;
+       int use_mmap = 1;
+       off_t mmap_offset = 0;
+       char *buf = NULL;
 
-       switch (v->type) {
-       case CFG_STRING:
-               if (!(buf = alloca(escaped_len(v->v.str)))) {
-                       log_error("temporary stack allocation for a config "
-                                 "string failed");
+       /* Only use mmap with regular files */
+       if (!(dev->flags & DEV_REGULAR) || size2)
+               use_mmap = 0;
+
+       if (use_mmap) {
+               mmap_offset = offset % lvm_getpagesize();
+               /* memory map the file */
+               fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
+                         MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);
+               if (fb == (caddr_t) (-1)) {
+                       log_sys_error("mmap", dev_name(dev));
+                       goto out;
+               }
+               fb = fb + mmap_offset;
+       } else {
+               if (!(buf = dm_malloc(size + size2))) {
+                       log_error("Failed to allocate circular buffer.");
                        return 0;
                }
-               line_append("\"%s\"", escape_double_quotes(buf, v->v.str));
-               break;
-
-       case CFG_FLOAT:
-               line_append("%f", v->v.r);
-               break;
-
-       case CFG_INT:
-               line_append("%" PRId64, v->v.i);
-               break;
-
-       case CFG_EMPTY_ARRAY:
-               line_append("[]");
-               break;
-
-       default:
-               log_error("_write_value: Unknown value type: %d", v->type);
-
-       }
-
-       return 1;
-}
-
-static int _write_config(const struct config_node *n, int only_one,
-                        struct output_line *outline, int level)
-{
-       char space[MAX_INDENT + 1];
-       int l = (level < MAX_INDENT) ? level : MAX_INDENT;
-       int i;
-
-       if (!n)
-               return 1;
-
-       for (i = 0; i < l; i++)
-               space[i] = '\t';
-       space[i] = '\0';
-
-       do {
-               if (!_line_start(outline))
-                       return_0;
-               line_append("%s%s", space, n->key);
-               if (!n->v) {
-                       /* it's a sub section */
-                       line_append(" {");
-                       if (!_line_end(outline))
-                               return_0;
-                       _write_config(n->child, 0, outline, level + 1);
-                       if (!_line_start(outline))
-                               return_0;
-                       line_append("%s}", space);
-               } else {
-                       /* it's a value */
-                       const struct config_value *v = n->v;
-                       line_append("=");
-                       if (v->next) {
-                               line_append("[");
-                               while (v) {
-                                       if (!_write_value(outline, v))
-                                               return_0;
-                                       v = v->next;
-                                       if (v)
-                                               line_append(", ");
-                               }
-                               line_append("]");
-                       } else
-                               if (!_write_value(outline, v))
-                                       return_0;
+               if (!dev_read_circular(dev, (uint64_t) offset, size,
+                                      (uint64_t) offset2, size2, buf)) {
+                       goto out;
                }
-               if (!_line_end(outline))
-                       return_0;
-               n = n->sib;
-       } while (n && !only_one);
-       /* FIXME: add error checking */
-       return 1;
-}
-
-int write_config_node(const struct config_node *cn, putline_fn putline, void *baton)
-{
-       struct output_line outline;
-       outline.fp = NULL;
-       if (!(outline.mem = dm_pool_create("config_line", 1024)))
-               return_0;
-       outline.putline = putline;
-       outline.putline_baton = baton;
-       if (!_write_config(cn, 0, &outline, 0)) {
-               dm_pool_destroy(outline.mem);
-               return_0;
+               fb = buf;
        }
-       dm_pool_destroy(outline.mem);
-       return 1;
-}
 
-int write_config_file(struct config_tree *cft, const char *file,
-                     int argc, char **argv)
-{
-       const struct config_node *cn;
-       int r = 1;
-       struct output_line outline;
-       outline.fp = NULL;
-       outline.putline = NULL;
-
-       if (!file)
-               file = "stdout";
-       else if (!(outline.fp = fopen(file, "w"))) {
-               log_sys_error("open", file);
-               return 0;
+       if (checksum_fn && checksum !=
+           (checksum_fn(checksum_fn(INITIAL_CRC, (const uint8_t *)fb, size),
+                        (const uint8_t *)(fb + size), size2))) {
+               log_error("%s: Checksum error", dev_name(dev));
+               goto out;
        }
 
-       if (!(outline.mem = dm_pool_create("config_line", 1024))) {
-               r = 0;
+       fe = fb + size + size2;
+       if (!dm_config_parse(cft, fb, fe))
                goto_out;
-       }
 
-       log_verbose("Dumping configuration to %s", file);
-       if (!argc) {
-               if (!_write_config(cft->root, 0, &outline, 0)) {
-                       log_error("Failure while writing to %s", file);
-                       r = 0;
-               }
-       } else while (argc--) {
-               if ((cn = find_config_node(cft->root, *argv))) {
-                       if (!_write_config(cn, 1, &outline, 0)) {
-                               log_error("Failure while writing to %s", file);
-                               r = 0;
-                       }
-               } else {
-                       log_error("Configuration node %s not found", *argv);
+       r = 1;
+
+      out:
+       if (!use_mmap)
+               dm_free(buf);
+       else {
+               /* unmap the file */
+               if (munmap(fb - mmap_offset, size + mmap_offset)) {
+                       log_sys_error("munmap", dev_name(dev));
                        r = 0;
                }
-               argv++;
-       }
-
-       dm_pool_destroy(outline.mem);
-
-out:
-       if (outline.fp && lvm_fclose(outline.fp, file)) {
-               stack;
-               r = 0;
        }
 
        return r;
 }
 
-/*
- * parser
- */
-static struct config_node *_file(struct parser *p)
-{
-       struct config_node *root = NULL, *n, *l = NULL;
-       while (p->t != TOK_EOF) {
-               if (!(n = _section(p)))
-                       return_0;
-
-               if (!root)
-                       root = n;
-               else
-                       l->sib = n;
-               n->parent = root;
-               l = n;
-       }
-       return root;
-}
-
-static struct config_node *_section(struct parser *p)
+int config_file_read(struct dm_config_tree *cft)
 {
-       /* IDENTIFIER SECTION_B_CHAR VALUE* SECTION_E_CHAR */
-       struct config_node *root, *n, *l = NULL;
-       if (!(root = _create_node(p->mem)))
-               return_0;
+       const char *filename = NULL;
+       struct config_file *cf = dm_config_get_custom(cft);
+       struct stat info;
+       int r;
 
-       if (!(root->key = _dup_tok(p)))
+       if (!config_file_check(cft, &filename, &info))
                return_0;
 
-       match(TOK_IDENTIFIER);
-
-       if (p->t == TOK_SECTION_B) {
-               match(TOK_SECTION_B);
-               while (p->t != TOK_SECTION_E) {
-                       if (!(n = _section(p)))
-                               return_0;
-
-                       if (!root->child)
-                               root->child = n;
-                       else
-                               l->sib = n;
-                       n->parent = root;
-                       l = n;
-               }
-               match(TOK_SECTION_E);
-       } else {
-               match(TOK_EQ);
-               if (!(root->v = _value(p)))
-                       return_0;
-       }
-
-       return root;
-}
-
-static struct config_value *_value(struct parser *p)
-{
-       /* '[' TYPE* ']' | TYPE */
-       struct config_value *h = NULL, *l, *ll = NULL;
-       if (p->t == TOK_ARRAY_B) {
-               match(TOK_ARRAY_B);
-               while (p->t != TOK_ARRAY_E) {
-                       if (!(l = _type(p)))
-                               return_0;
-
-                       if (!h)
-                               h = l;
-                       else
-                               ll->next = l;
-                       ll = l;
-
-                       if (p->t == TOK_COMMA)
-                               match(TOK_COMMA);
-               }
-               match(TOK_ARRAY_E);
-               /*
-                * Special case for an empty array.
-                */
-               if (!h) {
-                       if (!(h = _create_value(p->mem)))
-                               return NULL;
-
-                       h->type = CFG_EMPTY_ARRAY;
-               }
-
-       } else
-               h = _type(p);
-
-       return h;
-}
-
-static struct config_value *_type(struct parser *p)
-{
-       /* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */
-       struct config_value *v = _create_value(p->mem);
-       char *str;
-
-       if (!v)
-               return NULL;
-
-       switch (p->t) {
-       case TOK_INT:
-               v->type = CFG_INT;
-               v->v.i = strtoll(p->tb, NULL, 0);       /* FIXME: check error */
-               match(TOK_INT);
-               break;
-
-       case TOK_FLOAT:
-               v->type = CFG_FLOAT;
-               v->v.r = strtod(p->tb, NULL);   /* FIXME: check error */
-               match(TOK_FLOAT);
-               break;
-
-       case TOK_STRING:
-               v->type = CFG_STRING;
+       /* Nothing to do.  E.g. empty file. */
+       if (!filename)
+               return 1;
 
-               p->tb++, p->te--;       /* strip "'s */
-               if (!(v->v.str = _dup_tok(p)))
+       if (!cf->dev) {
+               if (!(cf->dev = dev_create_file(filename, NULL, NULL, 1)))
                        return_0;
-               p->te++;
-               match(TOK_STRING);
-               break;
 
-       case TOK_STRING_ESCAPED:
-               v->type = CFG_STRING;
-
-               p->tb++, p->te--;       /* strip "'s */
-               if (!(str = _dup_tok(p)))
+               if (!dev_open_readonly_buffered(cf->dev))
                        return_0;
-               unescape_double_quotes(str);
-               v->v.str = str;
-               p->te++;
-               match(TOK_STRING_ESCAPED);
-               break;
-
-       default:
-               log_error("Parse error at byte %" PRIptrdiff_t " (line %d): expected a value",
-                         p->tb - p->fb + 1, p->line);
-               return 0;
        }
-       return v;
-}
-
-static int _match_aux(struct parser *p, int t)
-{
-       if (p->t != t)
-               return 0;
-
-       _get_token(p, t);
-       return 1;
-}
-
-/*
- * tokeniser
- */
-static void _get_token(struct parser *p, int tok_prev)
-{
-       int values_allowed = 0;
-
-       const char *te;
-
-       p->tb = p->te;
-       _eat_space(p);
-       if (p->tb == p->fe || !*p->tb) {
-               p->t = TOK_EOF;
-               return;
-       }
-
-       /* Should next token be interpreted as value instead of identifier? */
-       if (tok_prev == TOK_EQ || tok_prev == TOK_ARRAY_B ||
-           tok_prev == TOK_COMMA)
-               values_allowed = 1;
-
-       p->t = TOK_INT;         /* fudge so the fall through for
-                                  floats works */
-
-       te = p->te;
-       switch (*te) {
-       case SECTION_B_CHAR:
-               p->t = TOK_SECTION_B;
-               te++;
-               break;
-
-       case SECTION_E_CHAR:
-               p->t = TOK_SECTION_E;
-               te++;
-               break;
-
-       case '[':
-               p->t = TOK_ARRAY_B;
-               te++;
-               break;
-
-       case ']':
-               p->t = TOK_ARRAY_E;
-               te++;
-               break;
-
-       case ',':
-               p->t = TOK_COMMA;
-               te++;
-               break;
-
-       case '=':
-               p->t = TOK_EQ;
-               te++;
-               break;
-
-       case '"':
-               p->t = TOK_STRING_ESCAPED;
-               te++;
-               while ((te != p->fe) && (*te) && (*te != '"')) {
-                       if ((*te == '\\') && (te + 1 != p->fe) &&
-                           *(te + 1))
-                               te++;
-                       te++;
-               }
-
-               if ((te != p->fe) && (*te))
-                       te++;
-               break;
-
-       case '\'':
-               p->t = TOK_STRING;
-               te++;
-               while ((te != p->fe) && (*te) && (*te != '\''))
-                       te++;
-
-               if ((te != p->fe) && (*te))
-                       te++;
-               break;
-
-       case '.':
-               p->t = TOK_FLOAT;
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-       case '+':
-       case '-':
-               if (values_allowed) {
-                       te++;
-                       while ((te != p->fe) && (*te)) {
-                               if (*te == '.') {
-                                       if (p->t == TOK_FLOAT)
-                                               break;
-                                       p->t = TOK_FLOAT;
-                               } else if (!isdigit((int) *te))
-                                       break;
-                               te++;
-                       }
-                       break;
-               }
-
-       default:
-               p->t = TOK_IDENTIFIER;
-               while ((te != p->fe) && (*te) && !isspace(*te) &&
-                      (*te != '#') && (*te != '=') &&
-                      (*te != SECTION_B_CHAR) &&
-                      (*te != SECTION_E_CHAR))
-                       te++;
-               break;
-       }
-
-       p->te = te;
-}
-
-static void _eat_space(struct parser *p)
-{
-       while ((p->tb != p->fe) && (*p->tb)) {
-               if (*p->te == '#')
-                       while ((p->te != p->fe) && (*p->te) && (*p->te != '\n'))
-                               p->te++;
-
-               else if (isspace(*p->te)) {
-                       while ((p->te != p->fe) && (*p->te) && isspace(*p->te)) {
-                               if (*p->te == '\n')
-                                       p->line++;
-                               p->te++;
-                       }
-               }
 
-               else
-                       return;
+       r = config_file_read_fd(cft, cf->dev, 0, (size_t) info.st_size, 0, 0,
+                               (checksum_fn_t) NULL, 0);
 
-               p->tb = p->te;
+       if (!cf->keep_open) {
+               if (!dev_close(cf->dev))
+                       stack;
+               cf->dev = NULL;
        }
-}
 
-/*
- * memory management
- */
-static struct config_value *_create_value(struct dm_pool *mem)
-{
-       return dm_pool_zalloc(mem, sizeof(struct config_value));
+       return r;
 }
 
-static struct config_node *_create_node(struct dm_pool *mem)
+time_t config_file_timestamp(struct dm_config_tree *cft)
 {
-       return dm_pool_zalloc(mem, sizeof(struct config_node));
+       struct config_file *cf = dm_config_get_custom(cft);
+       assert(cf);
+       return cf->timestamp;
 }
 
-static char *_dup_tok(struct parser *p)
-{
-       size_t len = p->te - p->tb;
-       char *str = dm_pool_alloc(p->mem, len + 1);
-       if (!str)
-               return_0;
-       strncpy(str, p->tb, len);
-       str[len] = '\0';
-       return str;
-}
-
-/*
- * utility functions
- */
-static const struct config_node *_find_config_node(const struct config_node *cn,
+const struct dm_config_node *find_config_tree_node(struct cmd_context *cmd,
                                                   const char *path)
 {
-       const char *e;
-       const struct config_node *cn_found = NULL;
-
-       while (cn) {
-               /* trim any leading slashes */
-               while (*path && (*path == sep))
-                       path++;
-
-               /* find the end of this segment */
-               for (e = path; *e && (*e != sep); e++) ;
-
-               /* hunt for the node */
-               cn_found = NULL;
-               while (cn) {
-                       if (_tok_match(cn->key, path, e)) {
-                               /* Inefficient */
-                               if (!cn_found)
-                                       cn_found = cn;
-                               else
-                                       log_warn("WARNING: Ignoring duplicate"
-                                                " config node: %s ("
-                                                "seeking %s)", cn->key, path);
-                       }
-
-                       cn = cn->sib;
-               }
-
-               if (cn_found && *e)
-                       cn = cn_found->child;
-               else
-                       break;  /* don't move into the last node */
-
-               path = e;
-       }
-
-       return cn_found;
-}
-
-static const struct config_node *_find_first_config_node(const struct config_node *cn1,
-                                                        const struct config_node *cn2,
-                                                        const char *path)
-{
-       const struct config_node *cn;
-
-       if (cn1 && (cn = _find_config_node(cn1, path)))
-               return cn;
-
-       if (cn2 && (cn = _find_config_node(cn2, path)))
-               return cn;
-
-       return NULL;
-}
-
-const struct config_node *find_config_node(const struct config_node *cn,
-                                          const char *path)
-{
-       return _find_config_node(cn, path);
-}
-
-static const char *_find_config_str(const struct config_node *cn1,
-                                   const struct config_node *cn2,
-                                   const char *path, const char *fail)
-{
-       const struct config_node *n = _find_first_config_node(cn1, cn2, path);
-
-       /* Empty strings are ignored */
-       if ((n && n->v && n->v->type == CFG_STRING) && (*n->v->v.str)) {
-               log_very_verbose("Setting %s to %s", path, n->v->v.str);
-               return n->v->v.str;
-       }
-
-       if (fail)
-               log_very_verbose("%s not found in config: defaulting to %s",
-                                path, fail);
-       return fail;
-}
-
-const char *find_config_str(const struct config_node *cn,
-                           const char *path, const char *fail)
-{
-       return _find_config_str(cn, NULL, path, fail);
-}
-
-static int64_t _find_config_int64(const struct config_node *cn1,
-                                 const struct config_node *cn2,
-                                 const char *path, int64_t fail)
-{
-       const struct config_node *n = _find_first_config_node(cn1, cn2, path);
-
-       if (n && n->v && n->v->type == CFG_INT) {
-               log_very_verbose("Setting %s to %" PRId64, path, n->v->v.i);
-               return n->v->v.i;
-       }
-
-       log_very_verbose("%s not found in config: defaulting to %" PRId64,
-                        path, fail);
-       return fail;
-}
-
-int find_config_int(const struct config_node *cn, const char *path, int fail)
-{
-       /* FIXME Add log_error message on overflow */
-       return (int) _find_config_int64(cn, NULL, path, (int64_t) fail);
-}
-
-static float _find_config_float(const struct config_node *cn1,
-                               const struct config_node *cn2,
-                               const char *path, float fail)
-{
-       const struct config_node *n = _find_first_config_node(cn1, cn2, path);
-
-       if (n && n->v && n->v->type == CFG_FLOAT) {
-               log_very_verbose("Setting %s to %f", path, n->v->v.r);
-               return n->v->v.r;
-       }
-
-       log_very_verbose("%s not found in config: defaulting to %f",
-                        path, fail);
-
-       return fail;
-
-}
-
-float find_config_float(const struct config_node *cn, const char *path,
-                       float fail)
-{
-       return _find_config_float(cn, NULL, path, fail);
-}
-
-const struct config_node *find_config_tree_node(struct cmd_context *cmd,
-                                         const char *path)
-{
-       return _find_first_config_node(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path);
+       return dm_config_tree_find_node(cmd->cft, path);
 }
 
 const char *find_config_tree_str(struct cmd_context *cmd,
                                 const char *path, const char *fail)
 {
-       return _find_config_str(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
+       return dm_config_tree_find_str(cmd->cft, path, fail);
 }
 
-int find_config_tree_int(struct cmd_context *cmd, const char *path,
-                        int fail)
+const char *find_config_tree_str_allow_empty(struct cmd_context *cmd,
+                                            const char *path, const char *fail)
 {
-       /* FIXME Add log_error message on overflow */
-       return (int) _find_config_int64(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, (int64_t) fail);
+       return dm_config_tree_find_str_allow_empty(cmd->cft, path, fail);
 }
 
-float find_config_tree_float(struct cmd_context *cmd, const char *path,
-                            float fail)
-{
-       return _find_config_float(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
-}
-
-static int _str_in_array(const char *str, const char * const values[])
-{
-       int i;
-
-       for (i = 0; values[i]; i++)
-               if (!strcasecmp(str, values[i]))
-                       return 1;
-
-       return 0;
-}
-
-static int _str_to_bool(const char *str, int fail)
+int find_config_tree_int(struct cmd_context *cmd, const char *path,
+                        int fail)
 {
-       const char * const _true_values[]  = { "y", "yes", "on", "true", NULL };
-       const char * const _false_values[] = { "n", "no", "off", "false", NULL };
-
-       if (_str_in_array(str, _true_values))
-               return 1;
-
-       if (_str_in_array(str, _false_values))
-               return 0;
-
-       return fail;
+       return dm_config_tree_find_int(cmd->cft, path, fail);
 }
 
-static int _find_config_bool(const struct config_node *cn1,
-                            const struct config_node *cn2,
-                            const char *path, int fail)
+int64_t find_config_tree_int64(struct cmd_context *cmd, const char *path, int64_t fail)
 {
-       const struct config_node *n = _find_first_config_node(cn1, cn2, path);
-       const struct config_value *v;
-
-       if (!n)
-               return fail;
-
-       v = n->v;
-
-       switch (v->type) {
-       case CFG_INT:
-               return v->v.i ? 1 : 0;
-
-       case CFG_STRING:
-               return _str_to_bool(v->v.str, fail);
-       }
-
-       return fail;
+       return dm_config_tree_find_int64(cmd->cft, path, fail);
 }
 
-int find_config_bool(const struct config_node *cn, const char *path, int fail)
+float find_config_tree_float(struct cmd_context *cmd, const char *path,
+                            float fail)
 {
-       return _find_config_bool(cn, NULL, path, fail);
+       return dm_config_tree_find_float(cmd->cft, path, fail);
 }
 
 int find_config_tree_bool(struct cmd_context *cmd, const char *path, int fail)
 {
-       return _find_config_bool(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
-}
-
-int get_config_uint32(const struct config_node *cn, const char *path,
-                     uint32_t *result)
-{
-       const struct config_node *n;
-
-       n = find_config_node(cn, path);
-
-       if (!n || !n->v || n->v->type != CFG_INT)
-               return 0;
-
-       *result = n->v->v.i;
-       return 1;
-}
-
-int get_config_uint64(const struct config_node *cn, const char *path,
-                     uint64_t *result)
-{
-       const struct config_node *n;
-
-       n = find_config_node(cn, path);
-
-       if (!n || !n->v || n->v->type != CFG_INT)
-               return 0;
-
-       *result = (uint64_t) n->v->v.i;
-       return 1;
-}
-
-int get_config_str(const struct config_node *cn, const char *path,
-                  const char **result)
-{
-       const struct config_node *n;
-
-       n = find_config_node(cn, path);
-
-       if (!n || !n->v || n->v->type != CFG_STRING)
-               return 0;
-
-       *result = n->v->v.str;
-       return 1;
+       return dm_config_tree_find_bool(cmd->cft, path, fail);
 }
 
 /* Insert cn2 after cn1 */
-static void _insert_config_node(struct config_node **cn1,
-                               struct config_node *cn2)
+static void _insert_config_node(struct dm_config_node **cn1,
+                               struct dm_config_node *cn2)
 {
        if (!*cn1) {
                *cn1 = cn2;
@@ -1170,10 +346,10 @@ static void _insert_config_node(struct config_node **cn1,
  * Merge section cn2 into section cn1 (which has the same name)
  * overwriting any existing cn1 nodes with matching names.
  */
-static void _merge_section(struct config_node *cn1, struct config_node *cn2)
+static void _merge_section(struct dm_config_node *cn1, struct dm_config_node *cn2)
 {
-       struct config_node *cn, *nextn, *oldn;
-       struct config_value *cv;
+       struct dm_config_node *cn, *nextn, *oldn;
+       struct dm_config_value *cv;
 
        for (cn = cn2->child; cn; cn = nextn) {
                nextn = cn->sib;
@@ -1187,7 +363,7 @@ static void _merge_section(struct config_node *cn1, struct config_node *cn2)
                        /* Ignore - we don't have any of these yet */
                        continue;
                /* Not already present? */
-               if (!(oldn = (struct config_node*)find_config_node(cn1->child, cn->key))) {
+               if (!(oldn = dm_config_find_node(cn1->child, cn->key))) {
                        _insert_config_node(&cn1->child, cn);
                        continue;
                }
@@ -1207,13 +383,13 @@ static void _merge_section(struct config_node *cn1, struct config_node *cn2)
        }
 }
 
-static int _match_host_tags(struct dm_list *tags, const struct config_node *tn)
+static int _match_host_tags(struct dm_list *tags, const struct dm_config_node *tn)
 {
-       const struct config_value *tv;
+       const struct dm_config_value *tv;
        const char *str;
 
        for (tv = tn->v; tv; tv = tv->next) {
-               if (tv->type != CFG_STRING)
+               if (tv->type != DM_CFG_STRING)
                        continue;
                str = tv->v.str;
                if (*str == '@')
@@ -1228,12 +404,12 @@ static int _match_host_tags(struct dm_list *tags, const struct config_node *tn)
 }
 
 /* Destructively merge a new config tree into an existing one */
-int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
-                     struct config_tree *newdata)
+int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft,
+                     struct dm_config_tree *newdata)
 {
-       const struct config_node *root = cft->root;
-       struct config_node *cn, *nextn, *oldn, *cn2;
-       const struct config_node *tn;
+       struct dm_config_node *root = cft->root;
+       struct dm_config_node *cn, *nextn, *oldn, *cn2;
+       const struct dm_config_node *tn;
 
        for (cn = newdata->root; cn; cn = nextn) {
                nextn = cn->sib;
@@ -1241,11 +417,11 @@ int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
                if (!strcmp(cn->key, "tags"))
                        continue;
                /* If there's a tags node, skip if host tags don't match */
-               if ((tn = find_config_node(cn->child, "tags"))) {
+               if ((tn = dm_config_find_node(cn->child, "tags"))) {
                        if (!_match_host_tags(&cmd->tags, tn))
                                continue;
                }
-               if (!(oldn = (struct config_node *)find_config_node(root, cn->key))) {
+               if (!(oldn = dm_config_find_node(root, cn->key))) {
                        _insert_config_node(&cft->root, cn);
                        /* Remove any "tags" nodes */
                        for (cn2 = cn->child; cn2; cn2 = cn2->sib) {
@@ -1266,117 +442,51 @@ int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
        return 1;
 }
 
-/*
- * Convert a token type to the char it represents.
- */
-static char _token_type_to_char(int type)
-{
-       switch (type) {
-               case TOK_SECTION_B:
-                       return SECTION_B_CHAR;
-               case TOK_SECTION_E:
-                       return SECTION_E_CHAR;
-               default:
-                       return 0;
-       }
-}
-
-/*
- * Returns:
- *  # of 'type' tokens in 'str'.
- */
-static unsigned _count_tokens(const char *str, unsigned len, int type)
-{
-       char c;
-
-       c = _token_type_to_char(type);
-
-       return count_chars(str, len, c);
-}
+static int _putline_fn(const char *line, void *baton) {
+       FILE *fp = baton;
+       fprintf(fp, "%s\n", line);
+       return 1;
+};
 
-const char *config_parent_name(const struct config_node *n)
+int config_write(struct dm_config_tree *cft, const char *file,
+                int argc, char **argv)
 {
-       return (n->parent ? n->parent->key : "(root)");
-}
-/*
- * Heuristic function to make a quick guess as to whether a text
- * region probably contains a valid config "section".  (Useful for
- * scanning areas of the disk for old metadata.)
- * Config sections contain various tokens, may contain other sections
- * and strings, and are delimited by begin (type 'TOK_SECTION_B') and
- * end (type 'TOK_SECTION_E') tokens.  As a quick heuristic, we just
- * count the number of begin and end tokens, and see if they are
- * non-zero and the counts match.
- * Full validation of the section should be done with another function
- * (for example, read_config_fd).
- *
- * Returns:
- *  0 - probably is not a valid config section
- *  1 - probably _is_ a valid config section
- */
-unsigned maybe_config_section(const char *str, unsigned len)
-{
-       int begin_count;
-       int end_count;
-
-       begin_count = _count_tokens(str, len, TOK_SECTION_B);
-       end_count = _count_tokens(str, len, TOK_SECTION_E);
+       const struct dm_config_node *cn;
+       int r = 1;
+       FILE *fp = NULL;
 
-       if (begin_count && end_count && (begin_count == end_count))
-               return 1;
-       else
+       if (!file) {
+               fp = stdout;
+               file = "stdout";
+       } else if (!(fp = fopen(file, "w"))) {
+               log_sys_error("open", file);
                return 0;
-}
-
-static struct config_value *_clone_config_value(struct dm_pool *mem, const struct config_value *v)
-{
-       struct config_value *new_cv;
-
-       if (!v)
-               return NULL;
-
-       if (!(new_cv = _create_value(mem))) {
-               log_error("Failed to clone config value.");
-               return NULL;
        }
 
-       new_cv->type = v->type;
-       if (v->type == CFG_STRING) {
-               if (!(new_cv->v.str = dm_pool_strdup(mem, v->v.str))) {
-                       log_error("Failed to clone config string value.");
-                       return NULL;
+       log_verbose("Dumping configuration to %s", file);
+       if (!argc) {
+               if (!dm_config_write_node(cft->root, _putline_fn, fp)) {
+                       log_error("Failure while writing to %s", file);
+                       r = 0;
                }
-       } else
-               new_cv->v = v->v;
-
-       if (v->next && !(new_cv->next = _clone_config_value(mem, v->next)))
-               return_NULL;
-
-       return new_cv;
-}
-
-struct config_node *clone_config_node(struct dm_pool *mem, const struct config_node *cn,
-                                     int siblings)
-{
-       struct config_node *new_cn;
-
-       if (!cn)
-               return NULL;
-
-       if (!(new_cn = _create_node(mem))) {
-               log_error("Failed to clone config node.");
-               return NULL;
+       } else while (argc--) {
+               if ((cn = dm_config_find_node(cft->root, *argv))) {
+                       if (!dm_config_write_one_node(cn, _putline_fn, fp)) {
+                               log_error("Failure while writing to %s", file);
+                               r = 0;
+                       }
+               } else {
+                       log_error("Configuration node %s not found", *argv);
+                       r = 0;
+               }
+               argv++;
        }
 
-       if ((cn->key && !(new_cn->key = dm_pool_strdup(mem, cn->key)))) {
-               log_error("Failed to clone config node key.");
-               return NULL;
+       if (fp && dm_fclose(fp)) {
+               stack;
+               r = 0;
        }
 
-       if ((cn->v && !(new_cn->v = _clone_config_value(mem, cn->v))) ||
-           (cn->child && !(new_cn->child = clone_config_node(mem, cn->child, 1))) ||
-           (siblings && cn->sib && !(new_cn->sib = clone_config_node(mem, cn->sib, siblings))))
-               return_NULL; /* 'new_cn' released with mem pool */
-
-       return new_cn;
+       return r;
 }
+
index f70deb011e08ee4684919f973d40894a96e95d80..d789ade3ab5e8c8c9a3ace2377b803798d70e5c4 100644 (file)
 struct device;
 struct cmd_context;
 
-enum {
-       CFG_STRING,
-       CFG_FLOAT,
-       CFG_INT,
-       CFG_EMPTY_ARRAY
-};
-
-struct config_value {
-       int type;
-       union {
-               int64_t i;
-               float r;
-               const char *str;
-       } v;
-       struct config_value *next;      /* for arrays */
-};
-
-struct config_node {
-       const char *key;
-       struct config_node *parent, *sib, *child;
-       struct config_value *v;
-};
-
-struct config_tree {
-       struct config_node *root;
-};
-
-struct config_tree_list {
-       struct dm_list list;
-       struct config_tree *cft;
-};
-
-struct config_tree *create_config_tree(const char *filename, int keep_open);
-struct config_tree *create_config_tree_from_string(struct cmd_context *cmd,
-                                                  const char *config_settings);
 int override_config_tree_from_string(struct cmd_context *cmd,
                                     const char *config_settings);
-void destroy_config_tree(struct config_tree *cft);
+struct dm_config_tree *remove_overridden_config_tree(struct cmd_context *cmd);
 
 typedef uint32_t (*checksum_fn_t) (uint32_t initial, const uint8_t *buf, uint32_t size);
 
-int read_config_fd(struct config_tree *cft, struct device *dev,
-                  off_t offset, size_t size, off_t offset2, size_t size2,
-                  checksum_fn_t checksum_fn, uint32_t checksum);
-
-int read_config_file(struct config_tree *cft);
-int write_config_file(struct config_tree *cft, const char *file,
-                     int argc, char **argv);
+struct dm_config_tree *config_file_open(const char *filename, int keep_open);
+int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
+                       off_t offset, size_t size, off_t offset2, size_t size2,
+                       checksum_fn_t checksum_fn, uint32_t checksum);
+       int config_file_read(struct dm_config_tree *cft);
+int config_write(struct dm_config_tree *cft, const char *file,
+                int argc, char **argv);
+void config_file_destroy(struct dm_config_tree *cft);
 
-typedef int (*putline_fn)(const char *line, void *baton);
-int write_config_node(const struct config_node *cn, putline_fn putline, void *baton);
+time_t config_file_timestamp(struct dm_config_tree *cft);
+int config_file_changed(struct dm_config_tree *cft);
+int config_file_check(struct dm_config_tree *cft, const char **filename, struct stat *info);
 
-time_t config_file_timestamp(struct config_tree *cft);
-int config_file_changed(struct config_tree *cft);
-int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
-                     struct config_tree *newdata);
 
-const struct config_node *find_config_node(const struct config_node *cn,
-                                          const char *path);
-const char *find_config_str(const struct config_node *cn, const char *path,
-                           const char *fail);
-int find_config_int(const struct config_node *cn, const char *path, int fail);
-float find_config_float(const struct config_node *cn, const char *path,
-                       float fail);
+int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft,
+                     struct dm_config_tree *newdata);
 
 /*
  * These versions check an override tree, if present, first.
  */
-const struct config_node *find_config_tree_node(struct cmd_context *cmd,
-                                               const char *path);
+const struct dm_config_node *find_config_tree_node(struct cmd_context *cmd,
+                                                  const char *path);
 const char *find_config_tree_str(struct cmd_context *cmd,
                                 const char *path, const char *fail);
+const char *find_config_tree_str_allow_empty(struct cmd_context *cmd,
+                                            const char *path, const char *fail);
 int find_config_tree_int(struct cmd_context *cmd, const char *path,
                         int fail);
+int64_t find_config_tree_int64(struct cmd_context *cmd, const char *path,
+                            int64_t fail);
 float find_config_tree_float(struct cmd_context *cmd, const char *path,
                             float fail);
 
-/*
- * Understands (0, ~0), (y, n), (yes, no), (on,
- * off), (true, false).
- */
-int find_config_bool(const struct config_node *cn, const char *path, int fail);
 int find_config_tree_bool(struct cmd_context *cmd, const char *path, int fail);
 
-int get_config_uint32(const struct config_node *cn, const char *path,
-                     uint32_t *result);
-
-int get_config_uint64(const struct config_node *cn, const char *path,
-                     uint64_t *result);
-
-int get_config_str(const struct config_node *cn, const char *path,
-                  const char **result);
-
-unsigned maybe_config_section(const char *str, unsigned len);
-
-const char *config_parent_name(const struct config_node *n);
-
-struct config_node *clone_config_node(struct dm_pool *mem, const struct config_node *cn,
-                                     int siblings);
 #endif
index a640112c35d127a3b2af86a75e65dc32462de1d3..9730a2d78348c9fb5f0f00e14497c5580913ac55 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
 
 #define DEFAULT_DEV_DIR "/dev"
 #define DEFAULT_PROC_DIR "/proc"
+#define DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV 1
 #define DEFAULT_SYSFS_SCAN 1
 #define DEFAULT_MD_COMPONENT_DETECTION 1
 #define DEFAULT_MD_CHUNK_ALIGNMENT 1
+#define DEFAULT_MULTIPATH_COMPONENT_DETECTION 1
 #define DEFAULT_IGNORE_SUSPENDED_DEVICES 1
 #define DEFAULT_DISABLE_AFTER_ERROR_COUNT 0
 #define DEFAULT_REQUIRE_RESTOREFILE_WITH_UUID 1
 #define DEFAULT_DATA_ALIGNMENT_OFFSET_DETECTION 1
 #define DEFAULT_DATA_ALIGNMENT_DETECTION 1
+#define DEFAULT_ISSUE_DISCARDS 0
+#define DEFAULT_PV_MIN_SIZE_KB 2048
 
 #define DEFAULT_LOCKING_LIB "liblvm2clusterlock.so"
 #define DEFAULT_FALLBACK_TO_LOCAL_LOCKING 1
 #define DEFAULT_PRIORITISE_WRITE_LOCKS 1
 #define DEFAULT_USE_MLOCKALL 0
 #define DEFAULT_METADATA_READ_ONLY 0
+#define DEFAULT_LVDISPLAY_SHOWS_FULL_DEVICE_PATH 0
 
+#define DEFAULT_MIRROR_SEGTYPE "mirror"
 #define DEFAULT_MIRRORLOG "disk"
 #define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate"
 #define DEFAULT_MIRROR_IMAGE_FAULT_POLICY "remove"
 #define DEFAULT_MIRROR_MAX_IMAGES 8 /* limited by kernel DM_KCOPYD_MAX_REGIONS */
+#define DEFAULT_RAID_FAULT_POLICY "warn"
+#define DEFAULT_DMEVENTD_RAID_LIB "libdevmapper-event-lvm2raid.so"
 #define DEFAULT_DMEVENTD_MIRROR_LIB "libdevmapper-event-lvm2mirror.so"
 #define DEFAULT_DMEVENTD_SNAPSHOT_LIB "libdevmapper-event-lvm2snapshot.so"
+#define DEFAULT_DMEVENTD_THIN_LIB "libdevmapper-event-lvm2thin.so"
 #define DEFAULT_DMEVENTD_MONITOR 1
 #define DEFAULT_BACKGROUND_POLLING 1
 
+#define DEFAULT_THIN_CHECK_OPTIONS "-q"
+#define DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
+#define DEFAULT_THIN_POOL_MAX_METADATA_SIZE (16 * 1024 * 1024)  /* KB */
+#define DEFAULT_THIN_POOL_MIN_METADATA_SIZE 2048  /* KB */
+#define DEFAULT_THIN_POOL_OPTIMAL_SIZE     (128 * 1024 * 1024) /* KB */
+
 #define DEFAULT_UMASK 0077
 
 #ifdef LVM1_FALLBACK
 #define DEFAULT_LABELSECTOR UINT64_C(1)
 #define DEFAULT_READ_AHEAD "auto"
 #define DEFAULT_UDEV_RULES 1
-#define DEFAULT_UDEV_SYNC 0
+#define DEFAULT_UDEV_SYNC 1
+#define DEFAULT_VERIFY_UDEV_OPERATIONS 0
+#define DEFAULT_RETRY_DEACTIVATION 1
+#define DEFAULT_ACTIVATION_CHECKS 0
 #define DEFAULT_EXTENT_SIZE 4096       /* In KB */
 #define DEFAULT_MAX_PV 0
 #define DEFAULT_MAX_LV 0
 #define DEFAULT_ALLOC_POLICY ALLOC_NORMAL
+#define DEFAULT_MIRROR_LOGS_REQUIRE_SEPARATE_PVS 0
+#define DEFAULT_MAXIMISE_CLING 1
 #define DEFAULT_CLUSTERED 0
 
 #define DEFAULT_MSG_PREFIX "  "
 
 #define DEFAULT_SYSLOG 1
 #define DEFAULT_VERBOSE 0
+#define DEFAULT_SILENT 0
 #define DEFAULT_LOGLEVEL 0
 #define DEFAULT_INDENT 1
 #define DEFAULT_ABORT_ON_INTERNAL_ERRORS 0
+#define DEFAULT_DETECT_INTERNAL_VG_CACHE_CORRUPTION 0
 #define DEFAULT_UNITS "h"
 #define DEFAULT_SUFFIX 1
 #define DEFAULT_HOSTTAGS 0
 #ifdef DEVMAPPER_SUPPORT
 #  define DEFAULT_ACTIVATION 1
 #  define DEFAULT_RESERVED_MEMORY 8192
-#  define DEFAULT_RESERVED_STACK 256
+#  define DEFAULT_RESERVED_STACK 64 /* KB */
 #  define DEFAULT_PROCESS_PRIORITY -18
 #else
 #  define DEFAULT_ACTIVATION 0
 #endif
 
+#define DEFAULT_USE_LINEAR_TARGET 1
 #define DEFAULT_STRIPE_FILLER "error"
 #define DEFAULT_MIRROR_REGION_SIZE 512 /* KB */
 #define DEFAULT_INTERVAL 15
 #define DEFAULT_REP_QUOTED 1
 #define DEFAULT_REP_SEPARATOR " "
 
-#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,mirror_log,copy_percent,convert_lv"
+#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,pool_lv,origin,data_percent,move_pv,mirror_log,copy_percent,convert_lv"
 #define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
 #define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free"
 #define DEFAULT_SEGS_COLS "lv_name,vg_name,lv_attr,stripes,segtype,seg_size"
 #define DEFAULT_PVSEGS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"
 
-#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,origin,snap_percent,move_pv,copy_percent,mirror_log,convert_lv,lv_uuid"
+#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,pool_lv,origin,data_percent,metadata_percent,move_pv,copy_percent,mirror_log,convert_lv,lv_uuid"
 #define DEFAULT_VGS_COLS_VERB "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid"
 #define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,dev_size,pv_uuid"
 #define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize"
 #define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate"
 #define DEFAULT_SNAPSHOT_AUTOEXTEND_THRESHOLD 100
 #define DEFAULT_SNAPSHOT_AUTOEXTEND_PERCENT 20
+#define DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD 100
+#define DEFAULT_THIN_POOL_AUTOEXTEND_PERCENT 20
 
 #endif                         /* _LVM_DEFAULTS_H */
index bfcdca604bc0e7e0a71894b6d4866df1039fa00c..9942f1a66a1e0087f86d9305f0e7b8ed71916c4e 100644 (file)
@@ -55,7 +55,7 @@ static uint32_t _shuffle(uint32_t k)
 #endif
 }
 
-static struct node **_lookup(struct node *const *c, uint32_t key,
+static struct node *const *_lookup(struct node *const *c, uint32_t key,
                             struct node **p)
 {
        *p = NULL;
@@ -71,20 +71,20 @@ static struct node **_lookup(struct node *const *c, uint32_t key,
                        c = &(*c)->r;
        }
 
-       return (struct node **)c;
+       return c;
 }
 
 void *btree_lookup(const struct btree *t, uint32_t k)
 {
        uint32_t key = _shuffle(k);
-       struct node *p, **c = _lookup(&t->root, key, &p);
+       struct node *p, *const *c = _lookup(&t->root, key, &p);
        return (*c) ? (*c)->data : NULL;
 }
 
 int btree_insert(struct btree *t, uint32_t k, void *data)
 {
        uint32_t key = _shuffle(k);
-       struct node *p, **c = _lookup(&t->root, key, &p), *n;
+       struct node *p, **c = (struct node **) _lookup(&t->root, key, &p), *n;
 
        if (!*c) {
                if (!(n = dm_pool_alloc(t->mem, sizeof(*n))))
index 81575cb9298915870c5a0afc3e24c45cafa4425e..dfce69c38967a8c6cec480d050efc3d6f4765bb8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -50,16 +50,13 @@ int str_list_add(struct dm_pool *mem, struct dm_list *sll, const char *str)
        return 1;
 }
 
-int str_list_del(struct dm_list *sll, const char *str)
+void str_list_del(struct dm_list *sll, const char *str)
 {
        struct dm_list *slh, *slht;
 
-       dm_list_iterate_safe(slh, slht, sll) {
+       dm_list_iterate_safe(slh, slht, sll)
                if (!strcmp(str, dm_list_item(slh, struct str_list)->str))
                         dm_list_del(slh);
-       }
-
-       return 1;
 }
 
 int str_list_dup(struct dm_pool *mem, struct dm_list *sllnew,
index f7180e21fe8214746cb5e884b31464935513e648..42f47da306e08e965c3b945f236278b954b62642 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.  
- * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -18,7 +18,7 @@
 
 struct dm_list *str_list_create(struct dm_pool *mem);
 int str_list_add(struct dm_pool *mem, struct dm_list *sll, const char *str);
-int str_list_del(struct dm_list *sll, const char *str);
+void str_list_del(struct dm_list *sll, const char *str);
 int str_list_match_item(const struct dm_list *sll, const char *str);
 int str_list_match_list(const struct dm_list *sll, const struct dm_list *sll2, const char **tag_matched);
 int str_list_lists_equal(const struct dm_list *sll, const struct dm_list *sll2);
index 962aa1e004e06202a74051d6fe67bcb8b8c69cdd..d08b07ff3495346577ba40340954cd504f484f04 100644 (file)
@@ -18,7 +18,6 @@
 #include "lvm-types.h"
 #include "btree.h"
 #include "filter.h"
-#include "filter-persistent.h"
 #include "toolcontext.h"
 
 #include <unistd.h>
@@ -48,11 +47,23 @@ static struct {
 
 } _cache;
 
-#define _alloc(x) dm_pool_zalloc(_cache.mem, (x))
+#define _zalloc(x) dm_pool_zalloc(_cache.mem, (x))
 #define _free(x) dm_pool_free(_cache.mem, (x))
 #define _strdup(x) dm_pool_strdup(_cache.mem, (x))
 
-static int _insert(const char *path, int rec);
+static int _insert(const char *path, int rec, int check_with_udev_db);
+
+/* Setup non-zero members of passed zeroed 'struct device' */
+static void _dev_init(struct device *dev, int max_error_count)
+{
+       dev->block_size = -1;
+       dev->fd = -1;
+       dev->read_ahead = -1;
+       dev->max_error_count = max_error_count;
+
+       dm_list_init(&dev->aliases);
+       dm_list_init(&dev->open_list);
+}
 
 struct device *dev_create_file(const char *filename, struct device *dev,
                               struct str_list *alias, int use_malloc)
@@ -61,11 +72,11 @@ struct device *dev_create_file(const char *filename, struct device *dev,
 
        if (allocate) {
                if (use_malloc) {
-                       if (!(dev = dm_malloc(sizeof(*dev)))) {
+                       if (!(dev = dm_zalloc(sizeof(*dev)))) {
                                log_error("struct device allocation failed");
                                return NULL;
                        }
-                       if (!(alias = dm_malloc(sizeof(*alias)))) {
+                       if (!(alias = dm_zalloc(sizeof(*alias)))) {
                                log_error("struct str_list allocation failed");
                                dm_free(dev);
                                return NULL;
@@ -76,13 +87,12 @@ struct device *dev_create_file(const char *filename, struct device *dev,
                                dm_free(alias);
                                return NULL;
                        }
-                       dev->flags = DEV_ALLOCED;
                } else {
-                       if (!(dev = _alloc(sizeof(*dev)))) {
+                       if (!(dev = _zalloc(sizeof(*dev)))) {
                                log_error("struct device allocation failed");
                                return NULL;
                        }
-                       if (!(alias = _alloc(sizeof(*alias)))) {
+                       if (!(alias = _zalloc(sizeof(*alias)))) {
                                log_error("struct str_list allocation failed");
                                _free(dev);
                                return NULL;
@@ -97,19 +107,9 @@ struct device *dev_create_file(const char *filename, struct device *dev,
                return NULL;
        }
 
-       dev->flags |= DEV_REGULAR;
-       dm_list_init(&dev->aliases);
+       _dev_init(dev, NO_DEV_ERROR_COUNT_LIMIT);
+       dev->flags = DEV_REGULAR | ((use_malloc) ? DEV_ALLOCED : 0);
        dm_list_add(&dev->aliases, &alias->list);
-       dev->end = UINT64_C(0);
-       dev->dev = 0;
-       dev->fd = -1;
-       dev->open_count = 0;
-       dev->error_count = 0;
-       dev->max_error_count = NO_DEV_ERROR_COUNT_LIMIT;
-       dev->block_size = -1;
-       dev->read_ahead = -1;
-       memset(dev->pvid, 0, sizeof(dev->pvid));
-       dm_list_init(&dev->open_list);
 
        return dev;
 }
@@ -118,21 +118,13 @@ static struct device *_dev_create(dev_t d)
 {
        struct device *dev;
 
-       if (!(dev = _alloc(sizeof(*dev)))) {
+       if (!(dev = _zalloc(sizeof(*dev)))) {
                log_error("struct device allocation failed");
                return NULL;
        }
-       dev->flags = 0;
-       dm_list_init(&dev->aliases);
+
+       _dev_init(dev, dev_disable_after_error_count());
        dev->dev = d;
-       dev->fd = -1;
-       dev->open_count = 0;
-       dev->max_error_count = dev_disable_after_error_count();
-       dev->block_size = -1;
-       dev->read_ahead = -1;
-       dev->end = UINT64_C(0);
-       memset(dev->pvid, 0, sizeof(dev->pvid));
-       dm_list_init(&dev->open_list);
 
        return dev;
 }
@@ -261,10 +253,19 @@ static int _compare_paths(const char *path0, const char *path1)
        if (slash1 < slash0)
                return 1;
 
-       strncpy(p0, path0, PATH_MAX);
-       strncpy(p1, path1, PATH_MAX);
-       s0 = &p0[0] + 1;
-       s1 = &p1[0] + 1;
+       strncpy(p0, path0, sizeof(p0) - 1);
+       p0[sizeof(p0) - 1] = '\0';
+       strncpy(p1, path1, sizeof(p1) - 1);
+       p1[sizeof(p1) - 1] = '\0';
+       s0 = p0 + 1;
+       s1 = p1 + 1;
+
+       /*
+        * If we reach here, both paths are the same length.
+        * Now skip past identical path components.
+        */
+       while (*s0 && *s0 == *s1)
+               s0++, s1++;
 
        /* We prefer symlinks - they exist for a reason!
         * So we prefer a shorter path before the first symlink in the name.
@@ -303,7 +304,7 @@ static int _compare_paths(const char *path0, const char *path1)
 
 static int _add_alias(struct device *dev, const char *path)
 {
-       struct str_list *sl = _alloc(sizeof(*sl));
+       struct str_list *sl = _zalloc(sizeof(*sl));
        struct str_list *strl;
        const char *oldpath;
        int prefer_old = 1;
@@ -319,8 +320,7 @@ static int _add_alias(struct device *dev, const char *path)
                }
        }
 
-       if (!(sl->str = dm_pool_strdup(_cache.mem, path)))
-               return_0;
+       sl->str = path;
 
        if (!dm_list_empty(&dev->aliases)) {
                oldpath = dm_list_item(dev->aliases.n, struct str_list)->str;
@@ -348,6 +348,7 @@ static int _insert_dev(const char *path, dev_t d)
        struct device *dev;
        static dev_t loopfile_count = 0;
        int loopfile = 0;
+       char *path_copy;
 
        /* Generate pretend device numbers for loopfiles */
        if (!d) {
@@ -374,12 +375,17 @@ static int _insert_dev(const char *path, dev_t d)
                }
        }
 
-       if (!loopfile && !_add_alias(dev, path)) {
+       if (!(path_copy = dm_pool_strdup(_cache.mem, path))) {
+               log_error("Failed to duplicate path string.");
+               return 0;
+       }
+
+       if (!loopfile && !_add_alias(dev, path_copy)) {
                log_error("Couldn't add alias to dev cache.");
                return 0;
        }
 
-       if (!dm_hash_insert(_cache.names, path, dev)) {
+       if (!dm_hash_insert(_cache.names, path_copy, dev)) {
                log_error("Couldn't add name to hash in dev cache.");
                return 0;
        }
@@ -437,7 +443,7 @@ static int _insert_dir(const char *dir)
                                return_0;
 
                        _collapse_slashes(path);
-                       r &= _insert(path, 1);
+                       r &= _insert(path, 1, 0);
                        dm_free(path);
 
                        free(dirent[n]);
@@ -468,7 +474,123 @@ static int _insert_file(const char *path)
        return 1;
 }
 
-static int _insert(const char *path, int rec)
+#ifdef UDEV_SYNC_SUPPORT
+
+static int _device_in_udev_db(const dev_t d)
+{
+       struct udev *udev;
+       struct udev_device *udev_device;
+
+       if (!(udev = udev_get_library_context()))
+               return_0;
+
+       if ((udev_device = udev_device_new_from_devnum(udev, 'b', d))) {
+               udev_device_unref(udev_device);
+               return 1;
+       }
+
+       return 0;
+}
+
+static int _insert_udev_dir(struct udev *udev, const char *dir)
+{
+       struct udev_enumerate *udev_enum = NULL;
+       struct udev_list_entry *device_entry, *symlink_entry;
+       const char *entry_name, *node_name, *symlink_name;
+       struct udev_device *device;
+       int r = 1;
+
+       if (!(udev_enum = udev_enumerate_new(udev)))
+               goto bad;
+
+       if (udev_enumerate_add_match_subsystem(udev_enum, "block") ||
+           udev_enumerate_scan_devices(udev_enum))
+               goto bad;
+
+       /*
+        * Report any missing information as "log_very_verbose" only, do not
+        * report it as a "warning" or "error" - the record could be removed
+        * by the time we ask for more info (node name, symlink name...).
+        * Whatever removes *any* block device in the system (even unrelated
+        * to our operation), we would have a warning/error on output then.
+        * That could be misleading. If there's really any problem with missing
+        * information from udev db, we can still have a look at the verbose log.
+        */
+       udev_list_entry_foreach(device_entry, udev_enumerate_get_list_entry(udev_enum)) {
+               entry_name = udev_list_entry_get_name(device_entry);
+
+               if (!(device = udev_device_new_from_syspath(udev, entry_name))) {
+                       log_very_verbose("udev failed to return a device for entry %s.",
+                                        entry_name);
+                       continue;
+               }
+
+               if (!(node_name = udev_device_get_devnode(device)))
+                       log_very_verbose("udev failed to return a device node for entry %s.",
+                                        entry_name);
+               else
+                       r &= _insert(node_name, 0, 0);
+
+               udev_list_entry_foreach(symlink_entry, udev_device_get_devlinks_list_entry(device)) {
+                       if (!(symlink_name = udev_list_entry_get_name(symlink_entry)))
+                               log_very_verbose("udev failed to return a symlink name for entry %s.",
+                                                entry_name);
+                       else
+                               r &= _insert(symlink_name, 0, 0);
+               }
+
+               udev_device_unref(device);
+       }
+
+       udev_enumerate_unref(udev_enum);
+       return r;
+
+bad:
+       log_error("Failed to enumerate udev device list.");
+       udev_enumerate_unref(udev_enum);
+       return 0;
+}
+
+static void _insert_dirs(struct dm_list *dirs)
+{
+       struct dir_list *dl;
+       struct udev *udev;
+       int with_udev;
+
+       with_udev = obtain_device_list_from_udev() &&
+                   (udev = udev_get_library_context());
+
+       dm_list_iterate_items(dl, &_cache.dirs) {
+               if (with_udev) {
+                       if (!_insert_udev_dir(udev, dl->dir))
+                               log_debug("%s: Failed to insert devices from "
+                                         "udev-managed directory to device "
+                                         "cache fully", dl->dir);
+               }
+               else if (!_insert_dir(dl->dir))
+                       log_debug("%s: Failed to insert devices to "
+                                 "device cache fully", dl->dir);
+       }
+}
+
+#else  /* UDEV_SYNC_SUPPORT */
+
+static int _device_in_udev_db(const dev_t d)
+{
+       return 0;
+}
+
+static void _insert_dirs(struct dm_list *dirs)
+{
+       struct dir_list *dl;
+
+       dm_list_iterate_items(dl, &_cache.dirs)
+               _insert_dir(dl->dir);
+}
+
+#endif /* UDEV_SYNC_SUPPORT */
+
+static int _insert(const char *path, int rec, int check_with_udev_db)
 {
        struct stat info;
        int r = 0;
@@ -478,6 +600,11 @@ static int _insert(const char *path, int rec)
                return 0;
        }
 
+       if (check_with_udev_db && !_device_in_udev_db(info.st_rdev)) {
+               log_very_verbose("%s: Not in udev db", path);
+               return 0;
+       }
+
        if (S_ISDIR(info.st_mode)) {    /* add a directory */
                /* check it's not a symbolic link */
                if (lstat(path, &info) < 0) {
@@ -515,8 +642,7 @@ static void _full_scan(int dev_scan)
        if (_cache.has_scanned && !dev_scan)
                return;
 
-       dm_list_iterate_items(dl, &_cache.dirs)
-               _insert_dir(dl->dir);
+       _insert_dirs(&_cache.dirs);
 
        dm_list_iterate_items(dl, &_cache.files)
                _insert_file(dl->dir);
@@ -540,8 +666,8 @@ void dev_cache_scan(int do_scan)
 
 static int _init_preferred_names(struct cmd_context *cmd)
 {
-       const struct config_node *cn;
-       const struct config_value *v;
+       const struct dm_config_node *cn;
+       const struct dm_config_value *v;
        struct dm_pool *scratch = NULL;
        const char **regex;
        unsigned count = 0;
@@ -550,14 +676,14 @@ static int _init_preferred_names(struct cmd_context *cmd)
        _cache.preferred_names_matcher = NULL;
 
        if (!(cn = find_config_tree_node(cmd, "devices/preferred_names")) ||
-           cn->v->type == CFG_EMPTY_ARRAY) {
+           cn->v->type == DM_CFG_EMPTY_ARRAY) {
                log_very_verbose("devices/preferred_names not found in config file: "
                                 "using built-in preferences");
                return 1;
        }
 
        for (v = cn->v; v; v = v->next) {
-               if (v->type != CFG_STRING) {
+               if (v->type != DM_CFG_STRING) {
                        log_error("preferred_names patterns must be enclosed in quotes");
                        return 0;
                }
@@ -684,7 +810,7 @@ int dev_cache_add_dir(const char *path)
                return 1;
        }
 
-       if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) {
+       if (!(dl = _zalloc(sizeof(*dl) + strlen(path) + 1))) {
                log_error("dir_list allocation failed");
                return 0;
        }
@@ -710,7 +836,7 @@ int dev_cache_add_loopfile(const char *path)
                return 1;
        }
 
-       if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) {
+       if (!(dl = _zalloc(sizeof(*dl) + strlen(path) + 1))) {
                log_error("dir_list allocation failed for file");
                return 0;
        }
@@ -760,7 +886,7 @@ const char *dev_name_confirmed(struct device *dev, int quiet)
                if (dm_list_size(&dev->aliases) > 1) {
                        dm_list_del(dev->aliases.n);
                        if (!r)
-                               _insert(name, 0);
+                               _insert(name, 0, obtain_device_list_from_udev());
                        continue;
                }
 
@@ -788,7 +914,7 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
        }
 
        if (!d) {
-               _insert(name, 0);
+               _insert(name, 0, obtain_device_list_from_udev());
                d = (struct device *) dm_hash_lookup(_cache.names, name);
                if (!d) {
                        _full_scan(0);
@@ -800,6 +926,39 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
                      f->passes_filter(f, d))) ? d : NULL;
 }
 
+static struct device *_dev_cache_seek_devt(dev_t dev)
+{
+       struct device *d = NULL;
+       struct dm_hash_node *n = dm_hash_get_first(_cache.names);
+       while (n) {
+               d = dm_hash_get_data(_cache.names, n);
+               if (d->dev == dev)
+                       return d;
+               n = dm_hash_get_next(_cache.names, n);
+       }
+       return NULL;
+}
+
+/*
+ * TODO This is very inefficient. We probably want a hash table indexed by
+ * major:minor for keys to speed up these lookups.
+ */
+struct device *dev_cache_get_by_devt(dev_t dev, struct dev_filter *f)
+{
+       struct device *d = _dev_cache_seek_devt(dev);
+
+       if (d && (d->flags & DEV_REGULAR))
+               return d;
+
+       if (!d) {
+               _full_scan(0);
+               d = _dev_cache_seek_devt(dev);
+       }
+
+       return (d && (!f || (d->flags & DEV_REGULAR) ||
+                     f->passes_filter(f, d))) ? d : NULL;
+}
+
 struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
 {
        struct dev_iter *di = dm_malloc(sizeof(*di));
@@ -811,21 +970,27 @@ struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
 
        if (dev_scan && !trust_cache()) {
                /* Flag gets reset between each command */
-               if (!full_scan_done())
-                       persistent_filter_wipe(f); /* Calls _full_scan(1) */
+               if (!full_scan_done()) {
+                       if (f && f->wipe)
+                               f->wipe(f); /* Calls _full_scan(1) */
+                       else
+                               _full_scan(1);
+               }
        } else
                _full_scan(0);
 
        di->current = btree_first(_cache.devices);
        di->filter = f;
-       di->filter->use_count++;
+       if (di->filter)
+               di->filter->use_count++;
 
        return di;
 }
 
 void dev_iter_destroy(struct dev_iter *iter)
 {
-       iter->filter->use_count--;
+       if (iter->filter)
+               iter->filter->use_count--;
        dm_free(iter);
 }
 
@@ -850,18 +1015,14 @@ struct device *dev_iter_get(struct dev_iter *iter)
 
 void dev_reset_error_count(struct cmd_context *cmd)
 {
-       struct dev_iter *iter;
-       struct device *dev;
+       struct dev_iter iter;
 
-       if (!(iter = dev_iter_create(cmd->filter, 0))) {
-               log_error("Resetting device error count failed");
+       if (!_cache.devices)
                return;
-       }
-
-       for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter))
-               dev->error_count = 0;
 
-       dev_iter_destroy(iter);
+       iter.current = btree_first(_cache.devices);
+       while (iter.current)
+               _iter_next(&iter)->error_count = 0;
 }
 
 int dev_fd(struct device *dev)
index c1c86d6af07dc61c94a54a16c3b64e9b2377a7ad..3267c9d3250e5aaada0d25890e413b1de9fa22e1 100644 (file)
@@ -17,6 +17,7 @@
 #define _LVM_DEV_CACHE_H
 
 #include "device.h"
+#include "lvm-wrappers.h"
 
 /*
  * predicate for devices.
@@ -24,8 +25,9 @@
 struct dev_filter {
        int (*passes_filter) (struct dev_filter * f, struct device * dev);
        void (*destroy) (struct dev_filter * f);
-       unsigned use_count;
+       void (*wipe) (struct dev_filter * f);
        void *private;
+       unsigned use_count;
 };
 
 /*
@@ -41,8 +43,12 @@ int dev_cache_has_scanned(void);
 
 int dev_cache_add_dir(const char *path);
 int dev_cache_add_loopfile(const char *path);
+__attribute__((nonnull(1)))
 struct device *dev_cache_get(const char *name, struct dev_filter *f);
 
+// TODO
+struct device *dev_cache_get_by_devt(dev_t device, struct dev_filter *f);
+
 void dev_set_preferred_name(struct str_list *sl, struct device *dev);
 
 /*
index eb80a8942bb87d97cf1ef05058b129e48f4796af..3bb9d65d8069c7bac4cf4b99847d5affe448b495 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -36,6 +36,9 @@
 #  ifndef BLKGETSIZE64         /* fs.h out-of-date */
 #    define BLKGETSIZE64 _IOR(0x12, 114, size_t)
 #  endif /* BLKGETSIZE64 */
+#  ifndef BLKDISCARD
+#    define BLKDISCARD _IO(0x12,119)
+#  endif
 #else
 #  include <sys/disk.h>
 #  define BLKBSZGET DKIOCGETBLOCKSIZE
@@ -57,7 +60,7 @@ static DM_LIST_INIT(_open_devices);
  * The standard io loop that keeps submitting an io until it's
  * all gone.
  *---------------------------------------------------------------*/
-static int _io(struct device_area *where, void *buffer, int should_write)
+static int _io(struct device_area *where, char *buffer, int should_write)
 {
        int fd = dev_fd(where->dev);
        ssize_t n = 0;
@@ -126,7 +129,7 @@ static int _get_block_size(struct device *dev, unsigned int *size)
 {
        const char *name = dev_name(dev);
 
-       if ((dev->block_size == -1)) {
+       if (dev->block_size == -1) {
                if (ioctl(dev_fd(dev), BLKBSZGET, &dev->block_size) < 0) {
                        log_sys_error("ioctl BLKBSZGET", name);
                        return 0;
@@ -161,10 +164,10 @@ static void _widen_region(unsigned int block_size, struct device_area *region,
                result->size += block_size - delta;
 }
 
-static int _aligned_io(struct device_area *where, void *buffer,
+static int _aligned_io(struct device_area *where, char *buffer,
                       int should_write)
 {
-       void *bounce, *bounce_buf;
+       char *bounce, *bounce_buf;
        unsigned int block_size = 0;
        uintptr_t mask;
        struct device_area widened;
@@ -195,7 +198,7 @@ static int _aligned_io(struct device_area *where, void *buffer,
         * Realign start of bounce buffer (using the extra sector)
         */
        if (((uintptr_t) bounce) & mask)
-               bounce = (void *) ((((uintptr_t) bounce) + mask) & ~mask);
+               bounce = (char *) ((((uintptr_t) bounce) + mask) & ~mask);
 
        /* channel the io through the bounce buffer */
        if (!_io(&widened, bounce, 0)) {
@@ -279,7 +282,7 @@ static int _dev_read_ahead_dev(struct device *dev, uint32_t *read_ahead)
                return 1;
        }
 
-       if (!dev_open(dev))
+       if (!dev_open_readonly(dev))
                return_0;
 
        if (ioctl(dev->fd, BLKRAGET, &read_ahead_long) < 0) {
@@ -289,15 +292,42 @@ static int _dev_read_ahead_dev(struct device *dev, uint32_t *read_ahead)
                return 0;
        }
 
-       if (!dev_close(dev))
-               stack;
-
        *read_ahead = (uint32_t) read_ahead_long;
        dev->read_ahead = read_ahead_long;
 
        log_very_verbose("%s: read_ahead is %u sectors",
                         dev_name(dev), *read_ahead);
 
+       if (!dev_close(dev))
+               stack;
+
+       return 1;
+}
+
+static int _dev_discard_blocks(struct device *dev, uint64_t offset_bytes, uint64_t size_bytes)
+{
+       uint64_t discard_range[2];
+
+       if (!dev_open(dev))
+               return_0;
+
+       discard_range[0] = offset_bytes;
+       discard_range[1] = size_bytes;
+
+       log_debug("Discarding %" PRIu64 " bytes offset %" PRIu64 " bytes on %s.",
+                 size_bytes, offset_bytes, dev_name(dev));
+       if (ioctl(dev->fd, BLKDISCARD, &discard_range) < 0) {
+               log_error("%s: BLKDISCARD ioctl at offset %" PRIu64 " size %" PRIu64 " failed: %s.",
+                         dev_name(dev), offset_bytes, size_bytes, strerror(errno));
+               if (!dev_close(dev))
+                       stack;
+               /* It doesn't matter if discard failed, so return success. */
+               return 1;
+       }
+
+       if (!dev_close(dev))
+               stack;
+
        return 1;
 }
 
@@ -329,6 +359,17 @@ int dev_get_read_ahead(struct device *dev, uint32_t *read_ahead)
        return _dev_read_ahead_dev(dev, read_ahead);
 }
 
+int dev_discard_blocks(struct device *dev, uint64_t offset_bytes, uint64_t size_bytes)
+{
+       if (!dev)
+               return 0;
+
+       if (dev->flags & DEV_REGULAR)
+               return 1;
+
+       return _dev_discard_blocks(dev, offset_bytes, size_bytes);
+}
+
 /* FIXME Unused
 int dev_get_sectsize(struct device *dev, uint32_t *size)
 {
@@ -390,16 +431,15 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
                }
 
                if (dev->open_count && !need_excl) {
-                       /* FIXME Ensure we never get here */
-                       log_error(INTERNAL_ERROR "%s already opened read-only",
-                                dev_name(dev));
+                       log_debug("%s already opened read-only. Upgrading "
+                                 "to read-write.", dev_name(dev));
                        dev->open_count++;
                }
 
                dev_close_immediate(dev);
        }
 
-       if (memlock())
+       if (critical_section())
                /* FIXME Make this log_error */
                log_verbose("dev_open(%s) called while suspended",
                         dev_name(dev));
@@ -409,17 +449,6 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
        else if (!(name = dev_name_confirmed(dev, quiet)))
                return_0;
 
-       if (!(dev->flags & DEV_REGULAR)) {
-               if (stat(name, &buf) < 0) {
-                       log_sys_error("%s: stat failed", name);
-                       return 0;
-               }
-               if (buf.st_rdev != dev->dev) {
-                       log_error("%s: device changed", name);
-                       return 0;
-               }
-       }
-
 #ifdef O_DIRECT_SUPPORT
        if (direct) {
                if (!(dev->flags & DEV_O_DIRECT_TESTED))
@@ -499,20 +528,27 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
 
 int dev_open_quiet(struct device *dev)
 {
-       int flags;
-
-       flags = vg_write_lock_held() ? O_RDWR : O_RDONLY;
-
-       return dev_open_flags(dev, flags, 1, 1);
+       return dev_open_flags(dev, O_RDWR, 1, 1);
 }
 
 int dev_open(struct device *dev)
 {
-       int flags;
+       return dev_open_flags(dev, O_RDWR, 1, 0);
+}
 
-       flags = vg_write_lock_held() ? O_RDWR : O_RDONLY;
+int dev_open_readonly(struct device *dev)
+{
+       return dev_open_flags(dev, O_RDONLY, 1, 0);
+}
+
+int dev_open_readonly_buffered(struct device *dev)
+{
+       return dev_open_flags(dev, O_RDONLY, 0, 0);
+}
 
-       return dev_open_flags(dev, flags, 1, 0);
+int dev_open_readonly_quiet(struct device *dev)
+{
+       return dev_open_flags(dev, O_RDONLY, 1, 1);
 }
 
 int dev_test_excl(struct device *dev)
@@ -550,7 +586,6 @@ static void _close(struct device *dev)
 
 static int _dev_close(struct device *dev, int immediate)
 {
-       struct lvmcache_info *info;
 
        if (dev->fd < 0) {
                log_error("Attempt to close device '%s' "
@@ -572,10 +607,7 @@ static int _dev_close(struct device *dev, int immediate)
 
        /* Close unless device is known to belong to a locked VG */
        if (immediate ||
-           (dev->open_count < 1 &&
-            (!(info = info_from_pvid(dev->pvid, 0)) ||
-             !info->vginfo ||
-             !vgname_is_locked(info->vginfo->vgname))))
+           (dev->open_count < 1 && !lvmcache_pvid_is_locked(dev->pvid)))
                _close(dev);
 
        return 1;
@@ -632,6 +664,8 @@ int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer)
        where.start = offset;
        where.size = len;
 
+       // fprintf(stderr, "READ: %s, %lld, %d\n", dev_name(dev), offset, len);
+
        ret = _aligned_io(&where, buffer, 0);
        if (!ret)
                _dev_inc_error_count(dev);
@@ -645,7 +679,7 @@ int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer)
  * 'buf' should be len+len2.
  */
 int dev_read_circular(struct device *dev, uint64_t offset, size_t len,
-                     uint64_t offset2, size_t len2, void *buf)
+                     uint64_t offset2, size_t len2, char *buf)
 {
        if (!dev_read(dev, offset, len, buf)) {
                log_error("Read from %s failed", dev_name(dev));
@@ -673,7 +707,7 @@ int dev_read_circular(struct device *dev, uint64_t offset, size_t len,
  */
 
 /* FIXME pre-extend the file */
-int dev_append(struct device *dev, size_t len, void *buffer)
+int dev_append(struct device *dev, size_t len, char *buffer)
 {
        int r;
 
index 6337992e55f05812d694c423b56380c512a5c8e2..10aae300a2c2f33a65d5263109363641a2add3fb 100644 (file)
@@ -23,7 +23,7 @@ int dev_is_luks(struct device *dev, uint64_t *signature)
        char buf[LUKS_SIGNATURE_SIZE];
        int ret = -1;
 
-       if (!dev_open(dev)) {
+       if (!dev_open_readonly(dev)) {
                stack;
                return -1;
        }
index 89b93410e2fc3f535a19dce8ed183679d8a88bff..247a8ac35e794fea1f4d88667105e0341f17f8c2 100644 (file)
@@ -27,6 +27,7 @@
 #define MD_RESERVED_SECTORS (MD_RESERVED_BYTES / 512)
 #define MD_NEW_SIZE_SECTORS(x) ((x & ~(MD_RESERVED_SECTORS - 1)) \
                                - MD_RESERVED_SECTORS)
+#define MD_MAX_SYSFS_SIZE 64
 
 static int _dev_has_md_magic(struct device *dev, uint64_t sb_offset)
 {
@@ -94,7 +95,7 @@ int dev_is_md(struct device *dev, uint64_t *sb)
        if (size < MD_RESERVED_SECTORS * 2)
                return 0;
 
-       if (!dev_open(dev)) {
+       if (!dev_open_readonly(dev)) {
                stack;
                return -1;
        }
@@ -176,7 +177,7 @@ static int _md_sysfs_attribute_scanf(const char *sysfs_dir,
                                     const char *attribute_fmt,
                                     void *attribute_value)
 {
-       char path[PATH_MAX+1], buffer[64];
+       char path[PATH_MAX+1], buffer[MD_MAX_SYSFS_SIZE];
        FILE *fp;
        int ret = 0;
 
@@ -231,15 +232,20 @@ static unsigned long dev_md_chunk_size(const char *sysfs_dir,
  */
 static int dev_md_level(const char *sysfs_dir, struct device *dev)
 {
+       char level_string[MD_MAX_SYSFS_SIZE];
        const char *attribute = "level";
        int level = -1;
 
        if (_md_sysfs_attribute_scanf(sysfs_dir, dev, attribute,
-                                     "raid%d", &level) != 1)
+                                     "%s", &level_string) != 1)
                return -1;
 
-       log_very_verbose("Device %s %s is raid%d.",
-                        dev_name(dev), attribute, level);
+       log_very_verbose("Device %s %s is %s.",
+                        dev_name(dev), attribute, level_string);
+
+       /*  We only care about raid - ignore linear/faulty/multipath etc. */
+       if (sscanf(level_string, "raid%d", &level) != 1)
+               return -1;
 
        return level;
 }
index b8ebcca52c376b012cb9e679dc2727a8dca3bcdb..346b60a0aff93c38b69b58c837398b44b825fab0 100644 (file)
@@ -14,8 +14,6 @@
 
 #include "lib.h"
 #include "metadata.h"
-#include "xlate.h"
-#include "filter.h"
 
 #ifdef linux
 
@@ -42,14 +40,15 @@ int dev_is_swap(struct device *dev, uint64_t *signature)
 {
        char buf[10];
        uint64_t size;
-       int page, ret = 0;
+       unsigned page;
+       int ret = 0;
 
        if (!dev_get_size(dev, &size)) {
                stack;
                return -1;
        }
 
-       if (!dev_open(dev)) {
+       if (!dev_open_readonly(dev)) {
                stack;
                return -1;
        }
index 80b447942d275007590b096566f026b007315d96..a87ae7ff6ac67910c927f147b9d31930e0d82ebd 100644 (file)
@@ -287,7 +287,7 @@ int get_primary_dev(const char *sysfs_dir,
        struct stat info;
        FILE *fp;
        uint32_t pri_maj, pri_min;
-       int ret = 0;
+       int size, ret = 0;
 
        /* check if dev is a partition */
        if (dm_snprintf(path, PATH_MAX, "%s/dev/block/%d:%d/partition",
@@ -309,11 +309,13 @@ int get_primary_dev(const char *sysfs_dir,
         * - basename ../../block/md0/md0  = md0
         * Parent's 'dev' sysfs attribute  = /sys/block/md0/dev
         */
-       if (readlink(dirname(path), temp_path, PATH_MAX) < 0) {
+       if ((size = readlink(dirname(path), temp_path, PATH_MAX)) < 0) {
                log_sys_error("readlink", path);
                return ret;
        }
 
+       temp_path[size] = '\0';
+
        if (dm_snprintf(path, PATH_MAX, "%s/block/%s/dev",
                        sysfs_dir, basename(dirname(temp_path))) < 0) {
                log_error("dm_snprintf dev failed");
@@ -345,7 +347,7 @@ int get_primary_dev(const char *sysfs_dir,
                          path, buffer);
                goto out;
        }
-       *result = MKDEV(pri_maj, pri_min);
+       *result = MKDEV((dev_t)pri_maj, pri_min);
        ret = 1;
 
 out:
@@ -359,7 +361,7 @@ static unsigned long _dev_topology_attribute(const char *attribute,
                                             const char *sysfs_dir,
                                             struct device *dev)
 {
-       const char *sysfs_fmt_str = "%s/dev/block/%d:%d/%s";
+       static const char sysfs_fmt_str[] = "%s/dev/block/%d:%d/%s";
        char path[PATH_MAX+1], buffer[64];
        FILE *fp;
        struct stat info;
@@ -453,6 +455,20 @@ unsigned long dev_optimal_io_size(const char *sysfs_dir,
                                       sysfs_dir, dev);
 }
 
+unsigned long dev_discard_max_bytes(const char *sysfs_dir,
+                                   struct device *dev)
+{
+       return _dev_topology_attribute("queue/discard_max_bytes",
+                                      sysfs_dir, dev);
+}
+
+unsigned long dev_discard_granularity(const char *sysfs_dir,
+                                     struct device *dev)
+{
+       return _dev_topology_attribute("queue/discard_granularity",
+                                      sysfs_dir, dev);
+}
+
 #else
 
 int get_primary_dev(const char *sysfs_dir,
@@ -479,4 +495,16 @@ unsigned long dev_optimal_io_size(const char *sysfs_dir,
        return 0UL;
 }
 
+unsigned long dev_discard_max_bytes(const char *sysfs_dir,
+                                   struct device *dev)
+{
+       return 0UL;
+}
+
+unsigned long dev_discard_granularity(const char *sysfs_dir,
+                                     struct device *dev)
+{
+       return 0UL;
+}
+
 #endif
index 694f503f58e61d7c495d8c77341ca46f3356c79c..8c32a03b422f9d26b0dba2ecd0f6b28a58377815 100644 (file)
@@ -68,11 +68,15 @@ struct device_area {
 int dev_get_size(const struct device *dev, uint64_t *size);
 int dev_get_sectsize(struct device *dev, uint32_t *size);
 int dev_get_read_ahead(struct device *dev, uint32_t *read_ahead);
+int dev_discard_blocks(struct device *dev, uint64_t offset_bytes, uint64_t size_bytes);
 
 /* Use quiet version if device number could change e.g. when opening LV */
 int dev_open(struct device *dev);
 int dev_open_quiet(struct device *dev);
 int dev_open_flags(struct device *dev, int flags, int direct, int quiet);
+int dev_open_readonly(struct device *dev);
+int dev_open_readonly_buffered(struct device *dev);
+int dev_open_readonly_quiet(struct device *dev);
 int dev_close(struct device *dev);
 int dev_close_immediate(struct device *dev);
 void dev_close_all(void);
@@ -83,9 +87,9 @@ const char *dev_name(const struct device *dev);
 
 int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer);
 int dev_read_circular(struct device *dev, uint64_t offset, size_t len,
-                     uint64_t offset2, size_t len2, void *buf);
+                     uint64_t offset2, size_t len2, char *buf);
 int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer);
-int dev_append(struct device *dev, size_t len, void *buffer);
+int dev_append(struct device *dev, size_t len, char *buffer);
 int dev_set(struct device *dev, uint64_t offset, size_t len, int value);
 void dev_flush(struct device *dev);
 
@@ -115,4 +119,10 @@ unsigned long dev_minimum_io_size(const char *sysfs_dir,
 unsigned long dev_optimal_io_size(const char *sysfs_dir,
                                  struct device *dev);
 
+unsigned long dev_discard_max_bytes(const char *sysfs_dir,
+                                   struct device *dev);
+
+unsigned long dev_discard_granularity(const char *sysfs_dir,
+                                     struct device *dev);
+
 #endif
index aae660a984e5d0f3434a4534d2f3d38019364e5d..b15ff71c88cdd36beb8ae71e89006eb00a7e47eb 100644 (file)
@@ -19,6 +19,7 @@
 #include "activate.h"
 #include "toolcontext.h"
 #include "segtype.h"
+#include "defaults.h"
 
 #define SIZE_BUF 128
 
@@ -44,15 +45,24 @@ uint64_t units_to_bytes(const char *units, char *unit_type)
 {
        char *ptr = NULL;
        uint64_t v;
+       double custom_value = 0;
+       uint64_t multiplier;
 
        if (isdigit(*units)) {
-               v = (uint64_t) strtod(units, &ptr);
+               custom_value = strtod(units, &ptr);
                if (ptr == units)
                        return 0;
+               v = (uint64_t) strtoull(units, NULL, 10);
+               if ((double) v == custom_value)
+                       custom_value = 0;       /* Use integer arithmetic */
                units = ptr;
        } else
                v = 1;
 
+       /* Only one units char permitted. */
+       if (units[0] && units[1])
+               return 0;
+
        if (v == 1)
                *unit_type = *units;
        else
@@ -61,68 +71,68 @@ uint64_t units_to_bytes(const char *units, char *unit_type)
        switch (*units) {
        case 'h':
        case 'H':
-               v = UINT64_C(1);
+               multiplier = v = UINT64_C(1);
                *unit_type = *units;
                break;
        case 'b':
        case 'B':
-               v *= UINT64_C(1);
+               multiplier = UINT64_C(1);
                break;
 #define KILO UINT64_C(1024)
        case 's':
        case 'S':
-               v *= (KILO/2);
+               multiplier = (KILO/2);
                break;
        case 'k':
-               v *= KILO;
+               multiplier = KILO;
                break;
        case 'm':
-               v *= KILO * KILO;
+               multiplier = KILO * KILO;
                break;
        case 'g':
-               v *= KILO * KILO * KILO;
+               multiplier = KILO * KILO * KILO;
                break;
        case 't':
-               v *= KILO * KILO * KILO * KILO;
+               multiplier = KILO * KILO * KILO * KILO;
                break;
        case 'p':
-               v *= KILO * KILO * KILO * KILO * KILO;
+               multiplier = KILO * KILO * KILO * KILO * KILO;
                break;
        case 'e':
-               v *= KILO * KILO * KILO * KILO * KILO * KILO;
+               multiplier = KILO * KILO * KILO * KILO * KILO * KILO;
                break;
 #undef KILO
 #define KILO UINT64_C(1000)
        case 'K':
-               v *= KILO;
+               multiplier = KILO;
                break;
        case 'M':
-               v *= KILO * KILO;
+               multiplier = KILO * KILO;
                break;
        case 'G':
-               v *= KILO * KILO * KILO;
+               multiplier = KILO * KILO * KILO;
                break;
        case 'T':
-               v *= KILO * KILO * KILO * KILO;
+               multiplier = KILO * KILO * KILO * KILO;
                break;
        case 'P':
-               v *= KILO * KILO * KILO * KILO * KILO;
+               multiplier = KILO * KILO * KILO * KILO * KILO;
                break;
        case 'E':
-               v *= KILO * KILO * KILO * KILO * KILO * KILO;
+               multiplier = KILO * KILO * KILO * KILO * KILO * KILO;
                break;
 #undef KILO
        default:
                return 0;
        }
 
-       if (*(units + 1))
-               return 0;
-
-       return v;
+       if (custom_value)
+               return (uint64_t) (custom_value * multiplier);
+       else
+               return v * multiplier;
 }
 
-const char alloc_policy_char(alloc_policy_t alloc)
+char alloc_policy_char(alloc_policy_t alloc)
 {
        int i;
 
@@ -476,7 +486,8 @@ void lvdisplay_colons(const struct logical_volume *lv)
                  lv->vg->name,
                  lv->name,
                  lv->vg->name,
-                 (lv->status & (LVM_READ | LVM_WRITE)) >> 8, inkernel ? 1 : 0,
+                 ((lv->status & (LVM_READ | LVM_WRITE)) >> 8) |
+                 ((inkernel && info.read_only) ? 4 : 0), inkernel ? 1 : 0,
                  /* FIXME lv->lv_number,  */
                  inkernel ? info.open_count : 0, lv->size, lv->le_count,
                  /* FIXME Add num allocated to struct! lv->lv_allocated_le, */
@@ -491,24 +502,52 @@ int lvdisplay_full(struct cmd_context *cmd,
        struct lvinfo info;
        int inkernel, snap_active = 0;
        char uuid[64] __attribute__((aligned(8)));
+       const char *access_str;
        struct lv_segment *snap_seg = NULL, *mirror_seg = NULL;
+       struct lv_segment *seg = NULL;
+       int lvm1compat;
        percent_t snap_percent;
+       int thin_data_active = 0, thin_metadata_active = 0;
+       percent_t thin_data_percent, thin_metadata_percent;
+       int thin_active = 0;
+       percent_t thin_percent;
 
        if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid)))
                return_0;
 
        inkernel = lv_info(cmd, lv, 0, &info, 1, 1) && info.exists;
 
+       if ((lv->status & LVM_WRITE) && inkernel && info.read_only)
+               access_str = "read/write (activated read only)";
+       else if (lv->status & LVM_WRITE)
+               access_str = "read/write";
+       else
+               access_str = "read only";
+
        log_print("--- Logical volume ---");
 
-       log_print("LV Name                %s%s/%s", lv->vg->cmd->dev_dir,
-                 lv->vg->name, lv->name);
-       log_print("VG Name                %s", lv->vg->name);
+       lvm1compat = find_config_tree_int(cmd, "global/lvdisplay_shows_full_device_path",
+                                         DEFAULT_LVDISPLAY_SHOWS_FULL_DEVICE_PATH);
+
+       if (lvm1compat)
+               /* /dev/vgname/lvname doen't actually exist for internal devices */
+               log_print("LV Name                %s%s/%s",
+                         lv->vg->cmd->dev_dir, lv->vg->name, lv->name);
+       else if (lv_is_visible(lv)) {
+               /* Thin pool does not have /dev/vg/name link */
+               if (!lv_is_thin_pool(lv))
+                       log_print("LV Path                %s%s/%s",
+                                 lv->vg->cmd->dev_dir,
+                                 lv->vg->name, lv->name);
+               log_print("LV Name                %s", lv->name);
+       } else
+               log_print("Internal LV Name       %s", lv->name);
 
+       log_print("VG Name                %s", lv->vg->name);
        log_print("LV UUID                %s", uuid);
-
-       log_print("LV Write Access        %s",
-                 (lv->status & LVM_WRITE) ? "read/write" : "read only");
+       log_print("LV Write Access        %s", access_str);
+       log_print("LV Creation host, time %s, %s",
+                 lv_host_dup(cmd->mem, lv), lv_time_dup(cmd->mem, lv));
 
        if (lv_is_origin(lv)) {
                log_print("LV snapshot status     source of");
@@ -520,10 +559,15 @@ int lvdisplay_full(struct cmd_context *cmd,
                                                               &snap_percent)))
                                if (snap_percent == PERCENT_INVALID)
                                        snap_active = 0;
-                       log_print("                       %s%s/%s [%s]",
-                                 lv->vg->cmd->dev_dir, lv->vg->name,
-                                 snap_seg->cow->name,
-                                 snap_active ? "active" : "INACTIVE");
+                       if (lvm1compat)
+                               log_print("                       %s%s/%s [%s]",
+                                         lv->vg->cmd->dev_dir, lv->vg->name,
+                                         snap_seg->cow->name,
+                                         snap_active ? "active" : "INACTIVE");
+                       else
+                               log_print("                       %s [%s]",
+                                         snap_seg->cow->name,
+                                         snap_active ? "active" : "INACTIVE");
                }
                snap_seg = NULL;
        } else if ((snap_seg = find_cow(lv))) {
@@ -533,10 +577,39 @@ int lvdisplay_full(struct cmd_context *cmd,
                        if (snap_percent == PERCENT_INVALID)
                                snap_active = 0;
 
-               log_print("LV snapshot status     %s destination for %s%s/%s",
-                         snap_active ? "active" : "INACTIVE",
-                         lv->vg->cmd->dev_dir, lv->vg->name,
-                         snap_seg->origin->name);
+               if (lvm1compat)
+                       log_print("LV snapshot status     %s destination for %s%s/%s",
+                                 snap_active ? "active" : "INACTIVE",
+                                 lv->vg->cmd->dev_dir, lv->vg->name,
+                                 snap_seg->origin->name);
+               else
+                       log_print("LV snapshot status     %s destination for %s",
+                                 snap_active ? "active" : "INACTIVE",
+                                 snap_seg->origin->name);
+       }
+
+       if (lv_is_thin_volume(lv)) {
+               seg = first_seg(lv);
+               log_print("LV Pool name           %s", seg->pool_lv->name);
+               if (seg->origin)
+                       log_print("LV Thin origin name    %s",
+                                 seg->origin->name);
+               if (inkernel)
+                       thin_active = lv_thin_percent(lv, 0, &thin_percent);
+       } else if (lv_is_thin_pool(lv)) {
+               if (inkernel) {
+                       thin_data_active = lv_thin_pool_percent(lv, 0, &thin_data_percent);
+                       thin_metadata_active = lv_thin_pool_percent(lv, 1, &thin_metadata_percent);
+               }
+               /* FIXME: display thin_pool targets transid for activated LV as well */
+               seg = first_seg(lv);
+               log_print("LV Pool transaction ID %" PRIu64, seg->transaction_id);
+               log_print("LV Pool metadata       %s", seg->metadata_lv->name);
+               log_print("LV Pool data           %s", seg_lv(seg, 0)->name);
+               log_print("LV Pool chunk size     %s",
+                         display_size(cmd, seg->chunk_size));
+               log_print("LV Zero new blocks     %s",
+                         seg->zero_new_blocks ? "yes" : "no");
        }
 
        if (inkernel && info.suspended)
@@ -556,6 +629,18 @@ int lvdisplay_full(struct cmd_context *cmd,
                  display_size(cmd,
                               snap_seg ? snap_seg->origin->size : lv->size));
 
+       if (thin_data_active)
+               log_print("Allocated pool data    %.2f%%",
+                         percent_to_float(thin_data_percent));
+
+       if (thin_metadata_active)
+               log_print("Allocated metadata     %.2f%%",
+                         percent_to_float(thin_metadata_percent));
+
+       if (thin_active)
+               log_print("Mapped size            %.2f%%",
+                         percent_to_float(thin_percent));
+
        log_print("Current LE             %u",
                  snap_seg ? snap_seg->origin->le_count : lv->le_count);
 
@@ -565,7 +650,7 @@ int lvdisplay_full(struct cmd_context *cmd,
                log_print("COW-table LE           %u", lv->le_count);
 
                if (snap_active)
-                       log_print("Allocated to snapshot  %.2f%% ",
+                       log_print("Allocated to snapshot  %.2f%%",
                                  percent_to_float(snap_percent));
 
                log_print("Snapshot chunk size    %s",
@@ -573,7 +658,7 @@ int lvdisplay_full(struct cmd_context *cmd,
        }
 
        if (lv->status & MIRRORED) {
-               mirror_seg = first_seg(lv);
+               mirror_seg = first_seg(lv);
                log_print("Mirrored volumes       %" PRIu32, mirror_seg->area_count);
                if (lv->status & CONVERTING)
                        log_print("LV type        Mirror undergoing conversion");
@@ -817,18 +902,27 @@ void display_segtypes(const struct cmd_context *cmd)
        }
 }
 
+/*
+ * Prompt for y or n from stdin.
+ * Defaults to 'no' in silent mode.
+ * All callers should support --yes and/or --force to override this.
+ */
 char yes_no_prompt(const char *prompt, ...)
 {
        int c = 0, ret = 0;
        va_list ap;
 
+       if (silent_mode())
+               return 'n';
+
        sigint_allow();
        do {
                if (c == '\n' || !c) {
                        va_start(ap, prompt);
-                       vprintf(prompt, ap);
+                       vfprintf(stderr, prompt, ap);
                        va_end(ap);
-                       fflush(stdout);
+                       fflush(stderr);
+                       ret = 0;
                }
 
                if ((c = getchar()) == EOF) {
@@ -837,15 +931,19 @@ char yes_no_prompt(const char *prompt, ...)
                }
 
                c = tolower(c);
-               if ((c == 'y') || (c == 'n'))
-                       ret = c;
-       } while (!ret || c != '\n');
+               if ((c == 'y') || (c == 'n')) {
+                       /* If both 'y' and 'n' given, begin again. */
+                       if (ret && c != ret)
+                               ret = -1;
+                       else
+                               ret = c;
+               }
+       } while (ret < 1 || c != '\n');
 
        sigint_restore();
 
        if (c != '\n')
-               printf("\n");
+               fprintf(stderr, "\n");
 
        return ret;
 }
-
index fb000a256137a963b81e7805d073b48219fd359f..8462901957b085f176dbcbe4f82e0556600c0803 100644 (file)
@@ -57,7 +57,7 @@ void display_segtypes(const struct cmd_context *cmd);
  * Allocation policy display conversion routines.
  */
 const char *get_alloc_string(alloc_policy_t alloc);
-const char alloc_policy_char(alloc_policy_t alloc);
+char alloc_policy_char(alloc_policy_t alloc);
 alloc_policy_t get_alloc_from_string(const char *str);
 
 char yes_no_prompt(const char *prompt, ...) __attribute__ ((format(printf, 1, 2)));
index add1df8cb7b2c37f2518b5cf9aac1b3d5b82fcf2..179f1a6fd10df5b6db9cd559046ee595ec848a29 100644 (file)
 #include "toolcontext.h"
 #include "segtype.h"
 #include "display.h"
-#include "text_export.h"
-#include "text_import.h"
 #include "config.h"
 #include "str_list.h"
-#include "targets.h"
-#include "lvm-string.h"
 #include "activate.h"
 #include "str_list.h"
-#include "metadata.h"
 
 static const char *_errseg_name(const struct lv_segment *seg)
 {
@@ -45,6 +40,7 @@ static int _errseg_add_target_line(struct dev_manager *dm __attribute__((unused)
                                struct cmd_context *cmd __attribute__((unused)),
                                void **target_state __attribute__((unused)),
                                struct lv_segment *seg __attribute__((unused)),
+                               const struct lv_activate_opts *laopts __attribute__((unused)),
                                struct dm_tree_node *node, uint64_t len,
                                uint32_t *pvmove_mirror_count __attribute__((unused)))
 {
@@ -99,7 +95,7 @@ static struct segtype_handler _error_ops = {
 
 struct segment_type *init_error_segtype(struct cmd_context *cmd)
 {
-       struct segment_type *segtype = dm_malloc(sizeof(*segtype));
+       struct segment_type *segtype = dm_zalloc(sizeof(*segtype));
 
        if (!segtype)
                return_NULL;
diff --git a/lib/filters/device-types.h b/lib/filters/device-types.h
new file mode 100644 (file)
index 0000000..9efbe68
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+typedef struct {
+       const char name[15];
+       const int8_t max_partitions;
+} device_info_t;
+
+/*
+ * Devices are only checked for partition tables if their minor number
+ * is a multiple of the number corresponding to their type below
+ * i.e. this gives the granularity of whole-device minor numbers.
+ * Use 1 if the device is not partitionable.
+ *
+ * The list can be supplemented with devices/types in the config file.
+ */
+static const device_info_t _device_info[] = {
+       {"ide", 64},            /* IDE disk */
+       {"sd", 16},             /* SCSI disk */
+       {"md", 1},              /* Multiple Disk driver (SoftRAID) */
+       {"mdp", 1},             /* Partitionable MD */
+       {"loop", 1},            /* Loop device */
+       {"dasd", 4},            /* DASD disk (IBM S/390, zSeries) */
+       {"dac960", 8},          /* DAC960 */
+       {"nbd", 16},            /* Network Block Device */
+       {"ida", 16},            /* Compaq SMART2 */
+       {"cciss", 16},          /* Compaq CCISS array */
+       {"ubd", 16},            /* User-mode virtual block device */
+       {"ataraid", 16},        /* ATA Raid */
+       {"drbd", 16},           /* Distributed Replicated Block Device */
+       {"emcpower", 16},       /* EMC Powerpath */
+       {"power2", 16},         /* EMC Powerpath */
+       {"i2o_block", 16},      /* i2o Block Disk */
+       {"iseries/vd", 8},      /* iSeries disks */
+       {"gnbd", 1},            /* Network block device */
+       {"ramdisk", 1},         /* RAM disk */
+       {"aoe", 16},            /* ATA over Ethernet */
+       {"device-mapper", 1},   /* Other mapped devices */
+       {"xvd", 16},            /* Xen virtual block device */
+       {"vdisk", 8},           /* SUN's LDOM virtual block device */
+       {"ps3disk", 16},        /* PlayStation 3 internal disk */
+       {"virtblk", 8},         /* VirtIO disk */
+       {"mmc", 16},            /* MMC block device */
+       {"blkext", 1},          /* Extended device partitions */
+       {"fio", 16},            /* Fusion */
+       {"mtip32xx", 16},       /* Micron PCIe SSDs */
+       {"", 0}
+};
index 130490af3e81604b67692387162f41ad8c55050e..3ed87870c8fc55821a93473b604e9364fa85c0f2 100644 (file)
@@ -64,7 +64,7 @@ struct dev_filter *composite_filter_create(int n, struct dev_filter **filters)
        memcpy(filters_copy, filters, sizeof(*filters) * n);
        filters_copy[n] = NULL;
 
-       if (!(cft = dm_malloc(sizeof(*cft)))) {
+       if (!(cft = dm_zalloc(sizeof(*cft)))) {
                log_error("compsoite filters allocation failed");
                dm_free(filters_copy);
                return NULL;
index 5cd8fb2335f7f9f9f2f445068a598f340971c486..d57489d85e63c5a9331e861b66664367a78c7474 100644 (file)
@@ -15,7 +15,6 @@
 
 #include "lib.h"
 #include "filter-md.h"
-#include "metadata.h"
 
 #ifdef linux
 
@@ -55,7 +54,7 @@ struct dev_filter *md_filter_create(void)
 {
        struct dev_filter *f;
 
-       if (!(f = dm_malloc(sizeof(*f)))) {
+       if (!(f = dm_zalloc(sizeof(*f)))) {
                log_error("md filter allocation failed");
                return NULL;
        }
diff --git a/lib/filters/filter-mpath.c b/lib/filters/filter-mpath.c
new file mode 100644 (file)
index 0000000..61a62d7
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "lib.h"
+#include "filter.h"
+#include "filter-mpath.h"
+#include "activate.h"
+
+#ifdef linux
+#include <dirent.h>
+
+#define MPATH_PREFIX "mpath-"
+
+static const char *get_sysfs_name(struct device *dev)
+{
+       const char *name;
+
+       if (!(name = strrchr(dev_name(dev), '/'))) {
+               log_error("Cannot find '/' in device name.");
+               return NULL;
+       }
+       name++;
+
+       if (!*name) {
+               log_error("Device name is not valid.");
+               return NULL;
+       }
+
+       return name;
+}
+
+static int get_sysfs_string(const char *path, char *buffer, int max_size)
+{
+       FILE *fp;
+       int r = 0;
+
+       if (!(fp = fopen(path, "r"))) {
+               log_sys_error("fopen", path);
+               return 0;
+       }
+
+       if (!fgets(buffer, max_size, fp))
+               log_sys_error("fgets", path);
+       else
+               r = 1;
+
+       if (fclose(fp))
+               log_sys_error("fclose", path);
+
+       return r;
+}
+
+static int get_sysfs_get_major_minor(const char *sysfs_dir, const char *kname, int *major, int *minor)
+{
+       char path[PATH_MAX], buffer[64];
+
+       if (dm_snprintf(path, sizeof(path), "%s/block/%s/dev", sysfs_dir, kname) < 0) {
+               log_error("Sysfs path string is too long.");
+               return 0;
+       }
+
+       if (!get_sysfs_string(path, buffer, sizeof(buffer)))
+               return_0;
+
+       if (sscanf(buffer, "%d:%d", major, minor) != 2) {
+               log_error("Failed to parse major minor from %s", buffer);
+               return 0;
+       }
+
+       return 1;
+}
+
+static int get_parent_mpath(const char *dir, char *name, int max_size)
+{
+       struct dirent *d;
+       DIR *dr;
+       int r = 0;
+
+       if (!(dr = opendir(dir))) {
+               log_sys_error("opendir", dir);
+               return 0;
+       }
+
+       *name = '\0';
+       while ((d = readdir(dr))) {
+               if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+                       continue;
+
+               /* There should be only one holder if it is multipath */
+               if (*name) {
+                       r = 0;
+                       break;
+               }
+
+               strncpy(name, d->d_name, max_size);
+               r = 1;
+       }
+
+       if (closedir(dr))
+               log_sys_error("closedir", dir);
+
+       return r;
+}
+
+static int dev_is_mpath(struct dev_filter *f, struct device *dev)
+{
+       const char *name;
+       char path[PATH_MAX+1];
+       char parent_name[PATH_MAX+1];
+       struct stat info;
+       const char *sysfs_dir = f->private;
+       int major, minor;
+
+       /* Limit this filter only to SCSI devices */
+       if (!major_is_scsi_device(MAJOR(dev->dev)))
+               return 0;
+
+       if (!(name = get_sysfs_name(dev)))
+               return_0;
+
+       if (dm_snprintf(path, PATH_MAX, "%s/block/%s/holders", sysfs_dir, name) < 0) {
+               log_error("Sysfs path to check mpath is too long.");
+               return 0;
+       }
+
+       /* also will filter out partitions */
+       if (stat(path, &info))
+               return 0;
+
+       if (!S_ISDIR(info.st_mode)) {
+               log_error("Path %s is not a directory.", path);
+               return 0;
+       }
+
+       if (!get_parent_mpath(path, parent_name, PATH_MAX))
+               return 0;
+
+       if (!get_sysfs_get_major_minor(sysfs_dir, parent_name, &major, &minor))
+               return_0;
+
+       if (major != dm_major()) {
+               log_error("mpath major %d is not dm major %d.", major, dm_major());
+               return 0;
+       }
+
+       return lvm_dm_prefix_check(major, minor, MPATH_PREFIX);
+}
+
+static int _ignore_mpath(struct dev_filter *f, struct device *dev)
+{
+       if (dev_is_mpath(f, dev) == 1) {
+               log_debug("%s: Skipping mpath component device", dev_name(dev));
+               return 0;
+       }
+
+       return 1;
+}
+
+static void _destroy(struct dev_filter *f)
+{
+       if (f->use_count)
+               log_error(INTERNAL_ERROR "Destroying mpath filter while in use %u times.", f->use_count);
+
+       dm_free(f->private);
+       dm_free(f);
+}
+
+struct dev_filter *mpath_filter_create(const char *sysfs_dir)
+{
+       struct dev_filter *f;
+
+       if (!*sysfs_dir) {
+               log_verbose("No proc filesystem found: skipping multipath filter");
+               return NULL;
+       }
+
+       if (!(f = dm_zalloc(sizeof(*f)))) {
+               log_error("mpath filter allocation failed");
+               return NULL;
+       }
+
+       f->passes_filter = _ignore_mpath;
+       f->destroy = _destroy;
+       f->use_count = 0;
+
+       if (!(f->private = dm_strdup(sysfs_dir))) {
+               log_error("Cannot duplicate sysfs dir.");
+               dm_free(f);
+               return NULL;
+       }
+
+       return f;
+}
+
+#else
+
+struct dev_filter *mpath_filter_create(const char *sysfs_dir __attribute__((unused)))
+{
+       return NULL;
+}
+
+#endif
diff --git a/lib/filters/filter-mpath.h b/lib/filters/filter-mpath.h
new file mode 100644 (file)
index 0000000..0b5373f
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LVM_FILTER_MPATH_H
+#define _LVM_FILTER_MPATH_H
+
+#include "dev-cache.h"
+
+struct dev_filter *mpath_filter_create(const char *sysfs_dir);
+
+#endif
+
index f3b1e05bd32a2b89be12253692e01b53ba3c9eac..d00a99a9ba34be8ec03ca2691aa2d87b194638ca 100644 (file)
@@ -51,7 +51,7 @@ static int _init_hash(struct pfilter *pf)
        return 1;
 }
 
-int persistent_filter_wipe(struct dev_filter *f)
+static void _persistent_filter_wipe(struct dev_filter *f)
 {
        struct pfilter *pf = (struct pfilter *) f->private;
 
@@ -60,17 +60,15 @@ int persistent_filter_wipe(struct dev_filter *f)
 
        /* Trigger complete device scan */
        dev_cache_scan(1);
-
-       return 1;
 }
 
-static int _read_array(struct pfilter *pf, struct config_tree *cft,
+static int _read_array(struct pfilter *pf, struct dm_config_tree *cft,
                       const char *path, void *data)
 {
-       const struct config_node *cn;
-       const struct config_value *cv;
+       const struct dm_config_node *cn;
+       const struct dm_config_value *cv;
 
-       if (!(cn = find_config_node(cft->root, path))) {
+       if (!(cn = dm_config_find_node(cft->root, path))) {
                log_very_verbose("Couldn't find %s array in '%s'",
                                 path, pf->file);
                return 0;
@@ -81,7 +79,7 @@ static int _read_array(struct pfilter *pf, struct config_tree *cft,
         * devices as we go.
         */
        for (cv = cn->v; cv; cv = cv->next) {
-               if (cv->type != CFG_STRING) {
+               if (cv->type != DM_CFG_STRING) {
                        log_verbose("Devices array contains a value "
                                    "which is not a string ... ignoring");
                        continue;
@@ -96,13 +94,24 @@ static int _read_array(struct pfilter *pf, struct config_tree *cft,
        return 1;
 }
 
-int persistent_filter_load(struct dev_filter *f, struct config_tree **cft_out)
+int persistent_filter_load(struct dev_filter *f, struct dm_config_tree **cft_out)
 {
        struct pfilter *pf = (struct pfilter *) f->private;
-       struct config_tree *cft;
+       struct dm_config_tree *cft;
        struct stat info;
        int r = 0;
 
+       if (obtain_device_list_from_udev()) {
+               if (!stat(pf->file, &info)) {
+                       log_very_verbose("Obtaining device list from "
+                                        "udev. Removing obolete %s.",
+                                        pf->file);
+                       if (unlink(pf->file) < 0 && errno != EROFS)
+                               log_sys_error("unlink", pf->file);
+               }
+               return 1;
+       }
+
        if (!stat(pf->file, &info))
                pf->ctime = info.st_ctime;
        else {
@@ -111,10 +120,10 @@ int persistent_filter_load(struct dev_filter *f, struct config_tree **cft_out)
                return_0;
        }
 
-       if (!(cft = create_config_tree(pf->file, 1)))
+       if (!(cft = config_file_open(pf->file, 1)))
                return_0;
 
-       if (!read_config_file(cft))
+       if (!config_file_read(cft))
                goto_out;
 
        _read_array(pf, cft, "persistent_filter_cache/valid_devices",
@@ -136,7 +145,7 @@ int persistent_filter_load(struct dev_filter *f, struct config_tree **cft_out)
        if (r && cft_out)
                *cft_out = cft;
        else
-               destroy_config_tree(cft);
+               config_file_destroy(cft);
        return r;
 }
 
@@ -162,7 +171,7 @@ static void _write_array(struct pfilter *pf, FILE *fp, const char *path,
                        first = 0;
                }
 
-               escape_double_quotes(buf, dm_hash_get_key(pf->devices, n));
+               dm_escape_double_quotes(buf, dm_hash_get_key(pf->devices, n));
                fprintf(fp, "\t\t\"%s\"", buf);
        }
 
@@ -175,11 +184,14 @@ int persistent_filter_dump(struct dev_filter *f, int merge_existing)
        struct pfilter *pf;
        char *tmp_file;
        struct stat info, info2;
-       struct config_tree *cft = NULL;
+       struct dm_config_tree *cft = NULL;
        FILE *fp;
        int lockfd;
        int r = 0;
 
+       if (obtain_device_list_from_udev())
+               return 1;
+
        if (!f)
                return_0;
        pf = (struct pfilter *) f->private;
@@ -257,7 +269,7 @@ out:
        fcntl_unlock_file(lockfd);
 
        if (cft)
-               destroy_config_tree(cft);
+               config_file_destroy(cft);
 
        return r;
 }
@@ -278,7 +290,10 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
        if (MAJOR(dev->dev) == dm_major()) {
                if (!l)
                        dm_list_iterate_items(sl, &dev->aliases)
-                               dm_hash_insert(pf->devices, sl->str, PF_GOOD_DEVICE);
+                               if (!dm_hash_insert(pf->devices, sl->str, PF_GOOD_DEVICE)) {
+                                       log_error("Failed to hash device to filter.");
+                                       return 0;
+                               }
                if (!device_is_usable(dev)) {
                        log_debug("%s: Skipping unusable device", dev_name(dev));
                        return 0;
@@ -291,7 +306,10 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
                l = pf->real->passes_filter(pf->real, dev) ?  PF_GOOD_DEVICE : PF_BAD_DEVICE;
 
                dm_list_iterate_items(sl, &dev->aliases)
-                       dm_hash_insert(pf->devices, sl->str, l);
+                       if (!dm_hash_insert(pf->devices, sl->str, l)) {
+                               log_error("Failed to hash alias to filter.");
+                               return 0;
+                       }
        }
 
        return (l == PF_BAD_DEVICE) ? 0 : 1;
@@ -318,13 +336,16 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
        struct dev_filter *f = NULL;
        struct stat info;
 
-       if (!(pf = dm_zalloc(sizeof(*pf))))
-               return_NULL;
+       if (!(pf = dm_zalloc(sizeof(*pf)))) {
+               log_error("Allocation of persistent filter failed.");
+               return NULL;
+       }
 
-       if (!(pf->file = dm_malloc(strlen(file) + 1)))
-               goto_bad;
+       if (!(pf->file = dm_strdup(file))) {
+               log_error("Filename duplication for persistent filter failed.");
+               goto bad;
+       }
 
-       strcpy(pf->file, file);
        pf->real = real;
 
        if (!(_init_hash(pf))) {
@@ -332,8 +353,10 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
                goto bad;
        }
 
-       if (!(f = dm_malloc(sizeof(*f))))
-               goto_bad;
+       if (!(f = dm_zalloc(sizeof(*f)))) {
+               log_error("Allocation of device filter for persistent filter failed.");
+               goto bad;
+       }
 
        /* Only merge cache file before dumping it if it changed externally. */
        if (!stat(pf->file, &info))
@@ -343,6 +366,7 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
        f->destroy = _persistent_destroy;
        f->use_count = 0;
        f->private = pf;
+       f->wipe = _persistent_filter_wipe;
 
        return f;
 
index a7f1245e0f56990770a31f9e367eeb63d25d16b1..c2eee3092b00ac8a91fa87d77628ef38bd55c046 100644 (file)
@@ -21,8 +21,7 @@
 struct dev_filter *persistent_filter_create(struct dev_filter *f,
                                            const char *file);
 
-int persistent_filter_wipe(struct dev_filter *f);
-int persistent_filter_load(struct dev_filter *f, struct config_tree **cft_out);
+int persistent_filter_load(struct dev_filter *f, struct dm_config_tree **cft_out);
 int persistent_filter_dump(struct dev_filter *f, int merge_existing);
 
 #endif
index e046c719f6d5d9e9f6fb42b1b4d9b1d5fa87084d..322119513905f7a3e4fcb11807ad66ce837bd264 100644 (file)
@@ -87,10 +87,10 @@ static int _extract_pattern(struct dm_pool *mem, const char *pat,
        return 1;
 }
 
-static int _build_matcher(struct rfilter *rf, const struct config_value *val)
+static int _build_matcher(struct rfilter *rf, const struct dm_config_value *val)
 {
        struct dm_pool *scratch;
-       const struct config_value *v;
+       const struct dm_config_value *v;
        char **regex;
        unsigned count = 0;
        int i, r = 0;
@@ -102,7 +102,7 @@ static int _build_matcher(struct rfilter *rf, const struct config_value *val)
         * count how many patterns we have.
         */
        for (v = val; v; v = v->next) {
-               if (v->type != CFG_STRING) {
+               if (v->type != DM_CFG_STRING) {
                        log_error("Filter patterns must be enclosed in quotes.");
                        goto out;
                }
@@ -110,16 +110,17 @@ static int _build_matcher(struct rfilter *rf, const struct config_value *val)
                count++;
        }
 
-       /*
-        * allocate space for them
-        */
-       if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count)))
-               goto_out;
+       /* Allocate space for them */
+       if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count))) {
+               log_error("Failed to allocate regex.");
+               goto out;
+       }
 
-       /*
-        * create the accept/reject bitset
-        */
-       rf->accept = dm_bitset_create(rf->mem, count);
+       /* Create the accept/reject bitset */
+       if (!(rf->accept = dm_bitset_create(rf->mem, count))) {
+               log_error("Failed to create bitset.");
+               goto out;
+       }
 
        /*
         * fill the array back to front because we
@@ -135,7 +136,7 @@ static int _build_matcher(struct rfilter *rf, const struct config_value *val)
        /*
         * build the matcher.
         */
-       if (!(rf->engine = dm_regex_create(rf->mem, (const char **) regex,
+       if (!(rf->engine = dm_regex_create(rf->mem, (const char * const*) regex,
                                           count)))
                goto_out;
        r = 1;
@@ -188,7 +189,7 @@ static void _regex_destroy(struct dev_filter *f)
        dm_pool_destroy(rf->mem);
 }
 
-struct dev_filter *regex_filter_create(const struct config_value *patterns)
+struct dev_filter *regex_filter_create(const struct dm_config_value *patterns)
 {
        struct dm_pool *mem = dm_pool_create("filter regex", 10 * 1024);
        struct rfilter *rf;
index a009c911be1da4d17cd4cdbe36de68765e24ec09..bb71f56f5c7542b682862c1952377765bccd2975 100644 (file)
@@ -27,6 +27,6 @@
  * r|.*|             - reject everything else
  */
 
-struct dev_filter *regex_filter_create(const struct config_value *patterns);
+struct dev_filter *regex_filter_create(const struct dm_config_value *patterns);
 
 #endif
index be8fbde5fb5abc7ab15ebf9dde78c877a72f2cc3..ebd16a2bad0448160a7e17a4e0da4ee48e0330a3 100644 (file)
@@ -14,7 +14,6 @@
 
 #include "lib.h"
 #include "filter-sysfs.h"
-#include "lvm-string.h"
 
 #ifdef linux
 
@@ -113,7 +112,9 @@ static struct dev_set *_dev_set_create(struct dm_pool *mem,
                return NULL;
 
        ds->mem = mem;
-       ds->sys_block = dm_pool_strdup(mem, sys_block);
+       if (!(ds->sys_block = dm_pool_strdup(mem, sys_block)))
+               return NULL;
+
        ds->sysfs_depth = sysfs_depth;
        ds->initialised = 0;
 
index c623d2a66d93023108daf0d279eb72dbdc0ebcf2..e33504531cea950088d4a4e49570f855f0b99b06 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
 #include <fcntl.h>
 #include <limits.h>
 
-#define NUMBER_OF_MAJORS 4096
+#include "device-types.h"
 
-/* 0 means LVM won't use this major number. */
-static int _max_partitions_by_major[NUMBER_OF_MAJORS];
+#define NUMBER_OF_MAJORS 4096
 
-typedef struct {
-       const char *name;
-       const int max_partitions;
-} device_info_t;
+#define PARTITION_SCSI_DEVICE (1 << 0)
+static struct {
+       int max_partitions; /* 0 means LVM won't use this major number. */
+       int flags;
+} _partitions[NUMBER_OF_MAJORS];
 
 static int _md_major = -1;
 static int _blkext_major = -1;
 static int _drbd_major = -1;
 static int _device_mapper_major = -1;
+static int _emcpower_major = -1;
 
 int dm_major(void)
 {
@@ -61,15 +62,15 @@ int dev_subsystem_part_major(const struct device *dev)
 {
        dev_t primary_dev;
 
-       if (MAJOR(dev->dev) == -1)
-               return 0;
-
        if (MAJOR(dev->dev) == _md_major)
                return 1;
 
        if (MAJOR(dev->dev) == _drbd_major)
                return 1;
 
+       if (MAJOR(dev->dev) == _emcpower_major)
+               return 1;
+
        if ((MAJOR(dev->dev) == _blkext_major) &&
            (get_primary_dev(sysfs_dir_path(), dev, &primary_dev)) &&
            (MAJOR(primary_dev) == _md_major))
@@ -86,51 +87,15 @@ const char *dev_subsystem_name(const struct device *dev)
        if (MAJOR(dev->dev) == _drbd_major)
                return "DRBD";
 
+       if (MAJOR(dev->dev) == _emcpower_major)
+               return "EMCPOWER";
+
        if (MAJOR(dev->dev) == _blkext_major)
                return "BLKEXT";
 
        return "";
 }
 
-/*
- * Devices are only checked for partition tables if their minor number
- * is a multiple of the number corresponding to their type below
- * i.e. this gives the granularity of whole-device minor numbers.
- * Use 1 if the device is not partitionable.
- *
- * The list can be supplemented with devices/types in the config file.
- */
-static const device_info_t device_info[] = {
-       {"ide", 64},            /* IDE disk */
-       {"sd", 16},             /* SCSI disk */
-       {"md", 1},              /* Multiple Disk driver (SoftRAID) */
-       {"mdp", 1},             /* Partitionable MD */
-       {"loop", 1},            /* Loop device */
-       {"dasd", 4},            /* DASD disk (IBM S/390, zSeries) */
-       {"dac960", 8},          /* DAC960 */
-       {"nbd", 16},            /* Network Block Device */
-       {"ida", 16},            /* Compaq SMART2 */
-       {"cciss", 16},          /* Compaq CCISS array */
-       {"ubd", 16},            /* User-mode virtual block device */
-       {"ataraid", 16},        /* ATA Raid */
-       {"drbd", 16},           /* Distributed Replicated Block Device */
-       {"emcpower", 16},       /* EMC Powerpath */
-       {"power2", 16},         /* EMC Powerpath */
-       {"i2o_block", 16},      /* i2o Block Disk */
-       {"iseries/vd", 8},      /* iSeries disks */
-       {"gnbd", 1},            /* Network block device */
-       {"ramdisk", 1},         /* RAM disk */
-       {"aoe", 16},            /* ATA over Ethernet */
-       {"device-mapper", 1},   /* Other mapped devices */
-       {"xvd", 16},            /* Xen virtual block device */
-       {"vdisk", 8},           /* SUN's LDOM virtual block device */
-       {"ps3disk", 16},        /* PlayStation 3 internal disk */
-       {"virtblk", 8},         /* VirtIO disk */
-       {"mmc", 16},            /* MMC block device */
-       {"blkext", 1},          /* Extended device partitions */
-       {NULL, 0}
-};
-
 static int _passes_lvm_type_device_filter(struct dev_filter *f __attribute__((unused)),
                                          struct device *dev)
 {
@@ -139,25 +104,25 @@ static int _passes_lvm_type_device_filter(struct dev_filter *f __attribute__((un
        uint64_t size;
 
        /* Is this a recognised device type? */
-       if (!_max_partitions_by_major[MAJOR(dev->dev)]) {
+       if (!_partitions[MAJOR(dev->dev)].max_partitions) {
                log_debug("%s: Skipping: Unrecognised LVM device type %"
                          PRIu64, name, (uint64_t) MAJOR(dev->dev));
                return 0;
        }
 
        /* Check it's accessible */
-       if (!dev_open_flags(dev, O_RDONLY, 0, 1)) {
+       if (!dev_open_readonly_quiet(dev)) {
                log_debug("%s: Skipping: open failed", name);
                return 0;
        }
-       
+
        /* Check it's not too small */
        if (!dev_get_size(dev, &size)) {
                log_debug("%s: Skipping: dev_get_size failed", name);
                goto out;
        }
 
-       if (size < PV_MIN_SIZE) {
+       if (size < pv_min_size()) {
                log_debug("%s: Skipping: Too small to hold a PV", name);
                goto out;
        }
@@ -171,12 +136,13 @@ static int _passes_lvm_type_device_filter(struct dev_filter *f __attribute__((un
        ret = 1;
 
       out:
-       dev_close(dev);
+       if (!dev_close(dev))
+               stack;
 
        return ret;
 }
 
-static int _scan_proc_dev(const char *proc, const struct config_node *cn)
+static int _scan_proc_dev(const char *proc, const struct dm_config_node *cn)
 {
        char line[80];
        char proc_devices[PATH_MAX];
@@ -185,20 +151,20 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
        int line_maj = 0;
        int blocksection = 0;
        size_t dev_len = 0;
-       const struct config_value *cv;
+       const struct dm_config_value *cv;
        const char *name;
-
+       char *nl;
 
        if (!*proc) {
                log_verbose("No proc filesystem found: using all block device "
                            "types");
                for (i = 0; i < NUMBER_OF_MAJORS; i++)
-                       _max_partitions_by_major[i] = 1;
+                       _partitions[i].max_partitions = 1;
                return 1;
        }
 
        /* All types unrecognised initially */
-       memset(_max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS);
+       memset(_partitions, 0, sizeof(_partitions));
 
        if (dm_snprintf(proc_devices, sizeof(proc_devices),
                         "%s/devices", proc) < 0) {
@@ -211,13 +177,26 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
                return 0;
        }
 
-       while (fgets(line, 80, pd) != NULL) {
+       while (fgets(line, sizeof(line), pd) != NULL) {
                i = 0;
-               while (line[i] == ' ' && line[i] != '\0')
+               while (line[i] == ' ')
                        i++;
 
                /* If it's not a number it may be name of section */
                line_maj = atoi(((char *) (line + i)));
+
+               if (line_maj < 0 || line_maj >= NUMBER_OF_MAJORS) {
+                       /*
+                        * Device numbers shown in /proc/devices are actually direct
+                        * numbers passed to registering function, however the kernel
+                        * uses only 12 bits, so use just 12 bits for major.
+                        */
+                       if ((nl = strchr(line, '\n'))) *nl = '\0';
+                       log_warn("WARNING: /proc/devices line: %s, replacing major with %d.",
+                                line, line_maj & (NUMBER_OF_MAJORS - 1));
+                       line_maj &= (NUMBER_OF_MAJORS - 1);
+               }
+
                if (!line_maj) {
                        blocksection = (line[i] == 'B') ? 1 : 0;
                        continue;
@@ -230,7 +209,7 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
                /* Find the start of the device major name */
                while (line[i] != ' ' && line[i] != '\0')
                        i++;
-               while (line[i] == ' ' && line[i] != '\0')
+               while (line[i] == ' ')
                        i++;
 
                /* Look for md device */
@@ -245,20 +224,28 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
                if (!strncmp("drbd", line + i, 4) && isspace(*(line + i + 4)))
                        _drbd_major = line_maj;
 
+               /* Look for EMC powerpath */
+               if (!strncmp("emcpower", line + i, 8) && isspace(*(line + i + 8)))
+                       _emcpower_major = line_maj;
+
                /* Look for device-mapper device */
                /* FIXME Cope with multiple majors */
                if (!strncmp("device-mapper", line + i, 13) && isspace(*(line + i + 13)))
                        _device_mapper_major = line_maj;
 
+               /* Major is SCSI device */
+               if (!strncmp("sd", line + i, 2) && isspace(*(line + i + 2)))
+                       _partitions[line_maj].flags |= PARTITION_SCSI_DEVICE;
+
                /* Go through the valid device names and if there is a
                   match store max number of partitions */
-               for (j = 0; device_info[j].name != NULL; j++) {
-                       dev_len = strlen(device_info[j].name);
+               for (j = 0; _device_info[j].name[0]; j++) {
+                       dev_len = strlen(_device_info[j].name);
                        if (dev_len <= strlen(line + i) &&
-                           !strncmp(device_info[j].name, line + i, dev_len) &&
+                           !strncmp(_device_info[j].name, line + i, dev_len) &&
                            (line_maj < NUMBER_OF_MAJORS)) {
-                               _max_partitions_by_major[line_maj] =
-                                   device_info[j].max_partitions;
+                               _partitions[line_maj].max_partitions =
+                                   _device_info[j].max_partitions;
                                break;
                        }
                }
@@ -268,7 +255,7 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
 
                /* Check devices/types for local variations */
                for (cv = cn->v; cv; cv = cv->next) {
-                       if (cv->type != CFG_STRING) {
+                       if (cv->type != DM_CFG_STRING) {
                                log_error("Expecting string in devices/types "
                                          "in config file");
                                if (fclose(pd))
@@ -278,7 +265,7 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
                        dev_len = strlen(cv->v.str);
                        name = cv->v.str;
                        cv = cv->next;
-                       if (!cv || cv->type != CFG_INT) {
+                       if (!cv || cv->type != DM_CFG_INT) {
                                log_error("Max partition count missing for %s "
                                          "in devices/types in config file",
                                          name);
@@ -297,7 +284,7 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
                        if (dev_len <= strlen(line + i) &&
                            !strncmp(name, line + i, dev_len) &&
                            (line_maj < NUMBER_OF_MAJORS)) {
-                               _max_partitions_by_major[line_maj] = cv->v.i;
+                               _partitions[line_maj].max_partitions = cv->v.i;
                                break;
                        }
                }
@@ -311,21 +298,40 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
 
 int max_partitions(int major)
 {
-       return _max_partitions_by_major[major];
+       if (major >= NUMBER_OF_MAJORS)
+               return 0;
+
+       return _partitions[major].max_partitions;
+}
+
+int major_is_scsi_device(int major)
+{
+       if (major >= NUMBER_OF_MAJORS)
+               return 0;
+
+       return (_partitions[major].flags & PARTITION_SCSI_DEVICE) ? 1 : 0;
+}
+
+static void _lvm_type_filter_destroy(struct dev_filter *f)
+{
+       if (f->use_count)
+               log_error(INTERNAL_ERROR "Destroying lvm_type filter while in use %u times.", f->use_count);
+
+       dm_free(f);
 }
 
 struct dev_filter *lvm_type_filter_create(const char *proc,
-                                         const struct config_node *cn)
+                                         const struct dm_config_node *cn)
 {
        struct dev_filter *f;
 
-       if (!(f = dm_malloc(sizeof(struct dev_filter)))) {
+       if (!(f = dm_zalloc(sizeof(struct dev_filter)))) {
                log_error("LVM type filter allocation failed");
                return NULL;
        }
 
        f->passes_filter = _passes_lvm_type_device_filter;
-       f->destroy = lvm_type_filter_destroy;
+       f->destroy = _lvm_type_filter_destroy;
        f->use_count = 0;
        f->private = NULL;
 
@@ -336,11 +342,3 @@ struct dev_filter *lvm_type_filter_create(const char *proc,
 
        return f;
 }
-
-void lvm_type_filter_destroy(struct dev_filter *f)
-{
-       if (f->use_count)
-               log_error(INTERNAL_ERROR "Destroying lvm_type filter while in use %u times.", f->use_count);
-
-       dm_free(f);
-}
index 07611f9eb167080cd9dcac6fb48f6ee16a1f59e3..cdbcfe837b3448bbaddf9fa1f83fd1e458a58623 100644 (file)
 #endif
 
 struct dev_filter *lvm_type_filter_create(const char *proc,
-                                         const struct config_node *cn);
-
-void lvm_type_filter_destroy(struct dev_filter *f);
+                                         const struct dm_config_node *cn);
 
 int dm_major(void);
 int md_major(void);
 int blkext_major(void);
 int max_partitions(int major);
+int major_is_scsi_device(int major);
 
 int dev_subsystem_part_major(const struct device *dev);
 const char *dev_subsystem_name(const struct device *dev);
index 071b39dd8c3c3da6b6a0c1f32d95f00a0c56fb15..0143ea09001c912408a6dea997f016aae5e5e1b8 100644 (file)
@@ -335,9 +335,9 @@ static void __update_lvmcache(const struct format_type *fmt,
                return;
        }
 
-       info->device_size = xlate32(dl->pvd.pv_size) << SECTOR_SHIFT;
-       dm_list_init(&info->mdas);
-       info->status &= ~CACHE_INVALID;
+       lvmcache_set_device_size(info, ((uint64_t)xlate32(dl->pvd.pv_size)) << SECTOR_SHIFT);
+       lvmcache_del_mdas(info);
+       lvmcache_make_valid(info);
 }
 
 static struct disk_list *__read_disk(const struct format_type *fmt,
@@ -415,7 +415,7 @@ struct disk_list *read_disk(const struct format_type *fmt, struct device *dev,
 {
        struct disk_list *dl;
 
-       if (!dev_open(dev))
+       if (!dev_open_readonly(dev))
                return_NULL;
 
        dl = __read_disk(fmt, dev, mem, vg_name);
@@ -451,6 +451,28 @@ static void _add_pv_to_list(struct dm_list *head, struct disk_list *data)
        dm_list_add(head, &data->list);
 }
 
+struct _read_pvs_in_vg_baton {
+       const char *vg_name;
+       struct dm_list *head;
+       struct disk_list *data;
+       struct dm_pool *mem;
+       int empty;
+};
+
+static int _read_pv_in_vg(struct lvmcache_info *info, void *baton)
+{
+       struct _read_pvs_in_vg_baton *b = baton;
+
+       b->empty = 0;
+
+       if (!lvmcache_device(info) ||
+           !(b->data = read_disk(lvmcache_fmt(info), lvmcache_device(info), b->mem, b->vg_name)))
+               return 0; /* stop here */
+
+       _add_pv_to_list(b->head, b->data);
+       return 1;
+}
+
 /*
  * Build a list of pv_d's structures, allocated from mem.
  * We keep track of the first object allocated from the pool
@@ -462,29 +484,31 @@ int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
 {
        struct dev_iter *iter;
        struct device *dev;
-       struct disk_list *data = NULL;
        struct lvmcache_vginfo *vginfo;
-       struct lvmcache_info *info;
+       struct _read_pvs_in_vg_baton baton;
+
+       baton.head = head;
+       baton.empty = 1;
+       baton.data = NULL;
+       baton.mem = mem;
+       baton.vg_name = vg_name;
 
        /* Fast path if we already saw this VG and cached the list of PVs */
-       if (vg_name && (vginfo = vginfo_from_vgname(vg_name, NULL)) &&
-           vginfo->infos.n) {
-               dm_list_iterate_items(info, &vginfo->infos) {
-                       dev = info->dev;
-                       if (!dev || !(data = read_disk(fmt, dev, mem, vg_name)))
-                               break;
-                       _add_pv_to_list(head, data);
-               }
+       if (vg_name && (vginfo = lvmcache_vginfo_from_vgname(vg_name, NULL))) {
+
+               lvmcache_foreach_pv(vginfo, _read_pv_in_vg, &baton);
 
-               /* Did we find the whole VG? */
-               if (!vg_name || is_orphan_vg(vg_name) ||
-                   (data && *data->pvd.vg_name &&
-                    dm_list_size(head) == data->vgd.pv_cur))
-                       return 1;
+               if (!baton.empty) {
+                       /* Did we find the whole VG? */
+                       if (!vg_name || is_orphan_vg(vg_name) ||
+                           (baton.data && *baton.data->pvd.vg_name &&
+                            dm_list_size(head) == baton.data->vgd.pv_cur))
+                               return 1;
 
-               /* Failed */
-               dm_list_init(head);
-               /* vgcache_del(vg_name); */
+                       /* Failed */
+                       dm_list_init(head);
+                       /* vgcache_del(vg_name); */
+               }
        }
 
        if (!(iter = dev_iter_create(filter, 1))) {
@@ -494,8 +518,8 @@ int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
 
        /* Otherwise do a complete scan */
        for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) {
-               if ((data = read_disk(fmt, dev, mem, vg_name))) {
-                       _add_pv_to_list(head, data);
+               if ((baton.data = read_disk(fmt, dev, mem, vg_name))) {
+                       _add_pv_to_list(head, baton.data);
                }
        }
        dev_iter_destroy(iter);
index fc14444898302697fcf535fad4875605bb356597..50626b5fa69316ec41a66eb6d8c91d9aa9d451b5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -177,84 +177,60 @@ out:
        return 0;
 }
 
-static struct volume_group *_build_vg(struct format_instance *fid,
-                                     struct dm_list *pvs,
-                                     struct dm_pool *mem)
+static struct volume_group *_format1_vg_read(struct format_instance *fid,
+                                    const char *vg_name,
+                                    struct metadata_area *mda __attribute__((unused)),
+                                    int single_device __attribute__((unused)))
 {
-       struct volume_group *vg = dm_pool_zalloc(mem, sizeof(*vg));
+       struct volume_group *vg;
        struct disk_list *dl;
+       DM_LIST_INIT(pvs);
+
+       /* Strip dev_dir if present */
+       if (vg_name)
+               vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir);
 
-       if (!vg)
+       if (!(vg = alloc_vg("format1_vg_read", fid->fmt->cmd, NULL)))
+               return_NULL;
+
+       if (!read_pvs_in_vg(fid->fmt, vg_name, fid->fmt->cmd->filter,
+                           vg->vgmem, &pvs))
                goto_bad;
 
-       if (dm_list_empty(pvs))
+       if (dm_list_empty(&pvs))
                goto_bad;
 
-       vg->cmd = fid->fmt->cmd;
-       vg->vgmem = mem;
-       vg->fid = fid;
-       vg->seqno = 0;
-       dm_list_init(&vg->pvs);
-       dm_list_init(&vg->lvs);
-       dm_list_init(&vg->tags);
-       dm_list_init(&vg->removed_pvs);
+       vg_set_fid(vg, fid);
 
-       if (!_check_vgs(pvs, vg))
+       if (!_check_vgs(&pvs, vg))
                goto_bad;
 
-       dl = dm_list_item(pvs->n, struct disk_list);
+       dl = dm_list_item(pvs.n, struct disk_list);
 
-       if (!import_vg(mem, vg, dl))
+       if (!import_vg(vg->vgmem, vg, dl))
                goto_bad;
 
-       if (!import_pvs(fid->fmt, mem, vg, pvs))
+       if (!import_pvs(fid->fmt, vg->vgmem, vg, &pvs))
                goto_bad;
 
-       if (!import_lvs(mem, vg, pvs))
+       if (!import_lvs(vg->vgmem, vg, &pvs))
                goto_bad;
 
-       if (!import_extents(fid->fmt->cmd, vg, pvs))
+       if (!import_extents(fid->fmt->cmd, vg, &pvs))
                goto_bad;
 
-       if (!import_snapshots(mem, vg, pvs))
+       if (!import_snapshots(vg->vgmem, vg, &pvs))
                goto_bad;
 
        /* Fix extents counts by adding missing PV if partial VG */
-       if ((vg->status & PARTIAL_VG) && !_fix_partial_vg(vg, pvs))
+       if ((vg->status & PARTIAL_VG) && !_fix_partial_vg(vg, &pvs))
                goto_bad;
 
        return vg;
 
-      bad:
-       dm_pool_free(mem, vg);
-       return NULL;
-}
-
-static struct volume_group *_format1_vg_read(struct format_instance *fid,
-                                    const char *vg_name,
-                                    struct metadata_area *mda __attribute__((unused)))
-{
-       struct dm_pool *mem = dm_pool_create("lvm1 vg_read", VG_MEMPOOL_CHUNK);
-       struct dm_list pvs;
-       struct volume_group *vg = NULL;
-       dm_list_init(&pvs);
-
-       if (!mem)
-               return_NULL;
-
-       /* Strip dev_dir if present */
-       vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir);
-
-       if (!read_pvs_in_vg
-           (fid->fmt, vg_name, fid->fmt->cmd->filter, mem, &pvs))
-               goto_bad;
-
-       if (!(vg = _build_vg(fid, &pvs, mem)))
-               goto_bad;
-
-       return vg;
 bad:
-       dm_pool_destroy(mem);
+       release_vg(vg);
+
        return NULL;
 }
 
@@ -331,8 +307,7 @@ static int _format1_vg_write(struct format_instance *fid, struct volume_group *v
 }
 
 static int _format1_pv_read(const struct format_type *fmt, const char *pv_name,
-                   struct physical_volume *pv, struct dm_list *mdas __attribute__((unused)),
-                   int scan_label_only __attribute__((unused)))
+                   struct physical_volume *pv, int scan_label_only __attribute__((unused)))
 {
        struct dm_pool *mem = dm_pool_create("lvm1 pv_read", 1024);
        struct disk_list *dl;
@@ -362,16 +337,14 @@ static int _format1_pv_read(const struct format_type *fmt, const char *pv_name,
        return r;
 }
 
-static int _format1_pv_setup(const struct format_type *fmt,
-                            uint64_t pe_start, uint32_t extent_count,
-                            uint32_t extent_size,
-                            unsigned long data_alignment __attribute__((unused)),
-                            unsigned long data_alignment_offset __attribute__((unused)),
-                            int pvmetadatacopies __attribute__((unused)),
-                            uint64_t pvmetadatasize __attribute__((unused)),
-                            unsigned metadataignore __attribute__((unused)),
-                            struct dm_list *mdas __attribute__((unused)),
-                            struct physical_volume *pv, struct volume_group *vg __attribute__((unused)))
+static int _format1_pv_initialise(const struct format_type * fmt,
+                                 int64_t label_sector __attribute__((unused)),
+                                 uint64_t pe_start,
+                                 uint32_t extent_count,
+                                 uint32_t extent_size,
+                                 unsigned long data_alignment __attribute__((unused)),
+                                 unsigned long data_alignment_offset __attribute__((unused)),
+                                 struct physical_volume * pv)
 {
        if (pv->size > MAX_PV_SIZE)
                pv->size--;
@@ -401,6 +374,13 @@ static int _format1_pv_setup(const struct format_type *fmt,
        return 1;
 }
 
+static int _format1_pv_setup(const struct format_type *fmt,
+                            struct physical_volume *pv,
+                            struct volume_group *vg)
+{
+       return _format1_pv_initialise(fmt, -1, 0, 0, vg->extent_size, 0, 0, pv);
+}
+
 static int _format1_lv_setup(struct format_instance *fid, struct logical_volume *lv)
 {
        uint64_t max_size = UINT_MAX;
@@ -422,25 +402,29 @@ static int _format1_lv_setup(struct format_instance *fid, struct logical_volume
        return 1;
 }
 
-static int _format1_pv_write(const struct format_type *fmt, struct physical_volume *pv,
-                    struct dm_list *mdas __attribute__((unused)), int64_t sector __attribute__((unused)))
+static int _format1_pv_write(const struct format_type *fmt, struct physical_volume *pv)
 {
        struct dm_pool *mem;
        struct disk_list *dl;
        struct dm_list pvs;
        struct lvmcache_info *info;
+       int pe_count, pe_size, pe_start;
+       int r = 1;
 
        if (!(info = lvmcache_add(fmt->labeller, (char *) &pv->id, pv->dev,
                                  pv->vg_name, NULL, 0)))
                return_0;
 
-       info->device_size = pv->size << SECTOR_SHIFT;
-       info->fmt = fmt;
-
-       dm_list_init(&info->mdas);
+       lvmcache_update_pv(info, pv, fmt);
+       lvmcache_del_mdas(info);
+       lvmcache_del_das(info);
 
        dm_list_init(&pvs);
 
+       pe_count = pv->pe_count;
+       pe_size = pv->pe_size;
+       pe_start = pv->pe_start;
+
        /* Ensure any residual PE structure is gone */
        pv->pe_size = pv->pe_count = 0;
        pv->pe_start = LVM1_PE_ALIGN;
@@ -453,6 +437,8 @@ static int _format1_pv_write(const struct format_type *fmt, struct physical_volu
 
        dl->mem = mem;
        dl->dev = pv->dev;
+       dm_list_init(&dl->uuids);
+       dm_list_init(&dl->lvds);
 
        if (!export_pv(fmt->cmd, mem, NULL, &dl->pvd, pv))
                goto_bad;
@@ -467,12 +453,18 @@ static int _format1_pv_write(const struct format_type *fmt, struct physical_volu
        if (!write_disks(fmt, &pvs))
                goto_bad;
 
-       dm_pool_destroy(mem);
-       return 1;
+       goto out;
 
       bad:
+       r = 0;
+
+      out:
+       pv->pe_size = pe_size;
+       pv->pe_count = pe_count;
+       pv->pe_start = pe_start;
+
        dm_pool_destroy(mem);
-       return 0;
+       return r;
 }
 
 static int _format1_vg_setup(struct format_instance *fid, struct volume_group *vg)
@@ -522,24 +514,19 @@ static struct metadata_area_ops _metadata_format1_ops = {
 };
 
 static struct format_instance *_format1_create_instance(const struct format_type *fmt,
-                                               const char *vgname __attribute__((unused)),
-                                               const char *vgid __attribute__((unused)),
-                                               void *private __attribute__((unused)))
+                                                       const struct format_instance_ctx *fic)
 {
        struct format_instance *fid;
        struct metadata_area *mda;
 
-       if (!(fid = dm_pool_alloc(fmt->cmd->mem, sizeof(*fid))))
+       if (!(fid = alloc_fid(fmt, fic)))
                return_NULL;
 
-       fid->fmt = fmt;
-       dm_list_init(&fid->metadata_areas_in_use);
-       dm_list_init(&fid->metadata_areas_ignored);
-
        /* Define a NULL metadata area */
-       if (!(mda = dm_pool_zalloc(fmt->cmd->mem, sizeof(*mda)))) {
-               dm_pool_free(fmt->cmd->mem, fid);
-               return_NULL;
+       if (!(mda = dm_pool_zalloc(fid->mem, sizeof(*mda)))) {
+               log_error("Unable to allocate metadata area structure "
+                         "for lvm1 format");
+               goto bad;
        }
 
        mda->ops = &_metadata_format1_ops;
@@ -548,19 +535,29 @@ static struct format_instance *_format1_create_instance(const struct format_type
        dm_list_add(&fid->metadata_areas_in_use, &mda->list);
 
        return fid;
+
+bad:
+       dm_pool_destroy(fid->mem);
+       return NULL;
 }
 
-static void _format1_destroy_instance(struct format_instance *fid __attribute__((unused)))
+static void _format1_destroy_instance(struct format_instance *fid)
 {
+       if (--fid->ref_count <= 1)
+               dm_pool_destroy(fid->mem);
 }
 
 static void _format1_destroy(struct format_type *fmt)
 {
+       if (fmt->orphan_vg)
+               free_orphan_vg(fmt->orphan_vg);
+
        dm_free(fmt);
 }
 
 static struct format_handler _format1_ops = {
        .pv_read = _format1_pv_read,
+       .pv_initialise = _format1_pv_initialise,
        .pv_setup = _format1_pv_setup,
        .pv_write = _format1_pv_write,
        .lv_setup = _format1_lv_setup,
@@ -579,9 +576,13 @@ struct format_type *init_format(struct cmd_context *cmd)
 #endif
 {
        struct format_type *fmt = dm_malloc(sizeof(*fmt));
+       struct format_instance_ctx fic;
+       struct format_instance *fid;
 
-       if (!fmt)
-               return_NULL;
+       if (!fmt) {
+               log_error("Failed to allocate format1 format type structure.");
+               return NULL;
+       }
 
        fmt->cmd = cmd;
        fmt->ops = &_format1_ops;
@@ -592,16 +593,38 @@ struct format_type *init_format(struct cmd_context *cmd)
                        FMT_RESTRICTED_READAHEAD;
        fmt->private = NULL;
 
+       dm_list_init(&fmt->mda_ops);
+
        if (!(fmt->labeller = lvm1_labeller_create(fmt))) {
                log_error("Couldn't create lvm1 label handler.");
+               dm_free(fmt);
                return NULL;
        }
 
        if (!(label_register_handler(FMT_LVM1_NAME, fmt->labeller))) {
                log_error("Couldn't register lvm1 label handler.");
+               fmt->labeller->ops->destroy(fmt->labeller);
+               dm_free(fmt);
                return NULL;
        }
 
+       if (!(fmt->orphan_vg = alloc_vg("format1_orphan", cmd, fmt->orphan_vg_name))) {
+               log_error("Couldn't create lvm1 orphan VG.");
+               dm_free(fmt);
+               return NULL;
+       }
+
+       fic.type = FMT_INSTANCE_AUX_MDAS;
+       fic.context.vg_ref.vg_name = fmt->orphan_vg_name;
+       fic.context.vg_ref.vg_id = NULL;
+
+       if (!(fid = _format1_create_instance(fmt, &fic))) {
+               _format1_destroy(fmt);
+               return_NULL;
+       }
+
+       vg_set_fid(fmt->orphan_vg, fid);
+
        log_very_verbose("Initialised format: %s", fmt->name);
 
        return fmt;
index d0b1b31fdb9f998ce12a13e8a7531aa362aaf9eb..5c5d890679470479070aa4cff21d56a450279b93 100644 (file)
@@ -25,7 +25,6 @@
 #include "segtype.h"
 #include "pv_alloc.h"
 #include "display.h"
-#include "lvmcache.h"
 #include "metadata.h"
 
 #include <time.h>
@@ -96,6 +95,8 @@ int import_pv(const struct format_type *fmt, struct dm_pool *mem,
        pv->pe_count = pvd->pe_total;
        pv->pe_alloc_count = 0;
        pv->pe_align = 0;
+        pv->is_labelled = 0; /* format1 PVs have no label */
+        pv->label_sector = 0;
 
        /* Fix up pv size if missing or impossibly large */
        if (!pv->size || pv->size > (1ULL << 62)) {
@@ -149,7 +150,7 @@ int export_pv(struct cmd_context *cmd, struct dm_pool *mem __attribute__((unused
 
        memcpy(pvd->pv_uuid, pv->id.uuid, ID_LEN);
 
-       if (pv->vg_name && !is_orphan(pv)) {
+       if (pv->vg_name && !is_orphan(pv) && !(pv->status & UNLABELLED_PV)) {
                if (!_check_vg_name(pv->vg_name))
                        return_0;
                strncpy((char *)pvd->vg_name, pv->vg_name, sizeof(pvd->vg_name));
@@ -225,7 +226,7 @@ int import_vg(struct dm_pool *mem,
        if (!(vg->name = dm_pool_strdup(mem, (char *)dl->pvd.vg_name)))
                return_0;
 
-       if (!(vg->system_id = dm_pool_alloc(mem, NAME_LEN)))
+       if (!(vg->system_id = dm_pool_zalloc(mem, NAME_LEN + 1)))
                return_0;
 
        *vg->system_id = '\0';
@@ -554,7 +555,7 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
 int import_snapshots(struct dm_pool *mem __attribute__((unused)), struct volume_group *vg,
                     struct dm_list *pvds)
 {
-       struct logical_volume *lvs[MAX_LV];
+       struct logical_volume *lvs[MAX_LV] = { 0 };
        struct disk_list *dl;
        struct lvd_list *ll;
        struct lv_disk *lvd;
@@ -562,7 +563,6 @@ int import_snapshots(struct dm_pool *mem __attribute__((unused)), struct volume_
        struct logical_volume *org, *cow;
 
        /* build an index of lv numbers */
-       memset(lvs, 0, sizeof(lvs));
        dm_list_iterate_items(dl, pvds) {
                dm_list_iterate_items(ll, &dl->lvds) {
                        lvd = &ll->lvd;
index 99723eef5de9482ba4437896d0357ec702f154f9..f0f4f65788c5437caf82deef5676cc33706dfca0 100644 (file)
@@ -63,8 +63,12 @@ static struct dm_hash_table *_create_lv_maps(struct dm_pool *mem,
                        goto_bad;
 
                lvm->lv = ll->lv;
+               /*
+                * Alloc 1 extra element, so the loop in _area_length() and
+                * _check_stripe() finds the last map member as noncontinuous.
+                */
                if (!(lvm->map = dm_pool_zalloc(mem, sizeof(*lvm->map)
-                                            * ll->lv->le_count)))
+                                            * (ll->lv->le_count + 1))))
                        goto_bad;
 
                if (!dm_hash_insert(maps, ll->lv->name, lvm))
@@ -114,7 +118,10 @@ static int _fill_maps(struct dm_hash_table *maps, struct volume_group *vg,
        uint32_t i, lv_num, le;
 
        dm_list_iterate_items(dl, pvds) {
-               pv = find_pv(vg, dl->dev);
+               if (!(pv = find_pv(vg, dl->dev))) {
+                       log_error("PV %s not found.", dl->dev->pvid);
+                       return 0;
+               }
                e = dl->extents;
 
                /* build an array of lv's for this pv */
@@ -218,8 +225,8 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
        while (le < lvm->lv->le_count) {
                len = _area_length(lvm, le);
 
-               if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv, le,
-                                            len, 0, 0, NULL, 1, len, 0, 0, 0, NULL))) {
+               if (!(seg = alloc_lv_segment(segtype, lvm->lv, le, len, 0, 0,
+                                            NULL, NULL, 1, len, 0, 0, 0, NULL))) {
                        log_error("Failed to allocate linear segment.");
                        return 0;
                }
@@ -288,10 +295,10 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
                                     area_len, first_area_le, total_area_len))
                        area_len++;
 
-               if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv,
+               if (!(seg = alloc_lv_segment(segtype, lvm->lv,
                                             lvm->stripes * first_area_le,
                                             lvm->stripes * area_len,
-                                            0, lvm->stripe_size, NULL,
+                                            0, lvm->stripe_size, NULL, NULL,
                                             lvm->stripes,
                                             area_len, 0, 0, 0, NULL))) {
                        log_error("Failed to allocate striped segment.");
index de9b206c7fd264d17f0dc3f11bd79df7d3fe0f1e..14a7eaf23bc90a26462f01a304095e58141153d6 100644 (file)
@@ -153,7 +153,7 @@ int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size,
 
                pvd->pe_start = _round_up(end, LVM1_PE_ALIGN);
 
-       } while ((pvd->pe_start + (pvd->pe_total * extent_size))
+       } while ((pvd->pe_start + ((uint64_t)pvd->pe_total * extent_size))
                 > pv->size);
 
        if (pvd->pe_total > MAX_PE_TOTAL) {
index 07596a54a815b03bcb9a3262286e0fec949db918..6138a05c2bb811a967e5a7dc1a56f53bea5b2e01 100644 (file)
@@ -77,12 +77,11 @@ static int _lvm1_read(struct labeller *l, struct device *dev, void *buf,
        if (!(info = lvmcache_add(l, (char *)pvd->pv_uuid, dev, vgname, vgid,
                                  exported)))
                return_0;
-       *label = info->label;
+       *label = lvmcache_get_label(info);
 
-       info->device_size = xlate32(pvd->pv_size) << SECTOR_SHIFT;
-       dm_list_init(&info->mdas);
-
-       info->status &= ~CACHE_INVALID;
+       lvmcache_set_device_size(info, ((uint64_t)xlate32(pvd->pv_size)) << SECTOR_SHIFT);
+       lvmcache_del_mdas(info);
+       lvmcache_make_valid(info);
 
        return 1;
 }
index 47570f5fa0341ee8454778bec68dd69c6f53d415..ed52554b61f21e7c2fdefa3613bc584936cd8053 100644 (file)
@@ -29,7 +29,7 @@ int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
        struct dm_list all_pvs;
        struct disk_list *dl;
        struct dm_pool *mem = dm_pool_create("lvm1 vg_number", 10 * 1024);
-       int numbers[MAX_VG], i, r = 0;
+       int i, r = 0, numbers[MAX_VG] = { 0 };
 
        dm_list_init(&all_pvs);
 
@@ -39,8 +39,6 @@ int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
        if (!read_pvs_in_vg(fid->fmt, NULL, filter, mem, &all_pvs))
                goto_out;
 
-       memset(numbers, 0, sizeof(numbers));
-
        dm_list_iterate_items(dl, &all_pvs) {
                if (!*dl->pvd.vg_name || !strcmp((char *)dl->pvd.vg_name, candidate_vg))
                        continue;
index ca8bfd73691d23e0c90cb7f3aa2d1be7845ceca9..a140384fe78e545665c65c07ce41b396a79917a6 100644 (file)
@@ -101,12 +101,11 @@ int read_pool_label(struct pool_list *pl, struct labeller *l,
                                  (char *) &vgid, 0)))
                return_0;
        if (label)
-               *label = info->label;
+               *label = lvmcache_get_label(info);
 
-       info->device_size = xlate32_be(pd->pl_blocks) << SECTOR_SHIFT;
-       dm_list_init(&info->mdas);
-
-       info->status &= ~CACHE_INVALID;
+       lvmcache_set_device_size(info, ((uint64_t)xlate32_be(pd->pl_blocks)) << SECTOR_SHIFT);
+       lvmcache_del_mdas(info);
+       lvmcache_make_valid(info);
 
        pl->dev = dev;
        pl->pv = NULL;
@@ -236,68 +235,92 @@ void get_pool_uuid(char *uuid, uint64_t poolid, uint32_t spid, uint32_t devid)
 
 }
 
-static int _read_vg_pds(const struct format_type *fmt, struct dm_pool *mem,
-                       struct lvmcache_vginfo *vginfo, struct dm_list *head,
-                       uint32_t *devcount)
+struct _read_pool_pv_baton {
+       const struct format_type *fmt;
+       struct dm_pool *mem, *tmpmem;
+       struct pool_list *pl;
+       struct dm_list *head;
+       const char *vgname;
+       uint32_t *sp_devs;
+       int sp_count;
+       int failed;
+       int empty;
+};
+
+static int _read_pool_pv(struct lvmcache_info *info, void *baton)
 {
-       struct lvmcache_info *info;
-       struct pool_list *pl = NULL;
-       struct dm_pool *tmpmem;
+       struct _read_pool_pv_baton *b = baton;
+
+       b->empty = 0;
+
+       if (lvmcache_device(info) &&
+           !(b->pl = read_pool_disk(b->fmt, lvmcache_device(info), b->mem, b->vgname)))
+               return 0;
+
+       /*
+        * We need to keep track of the total expected number
+        * of devices per subpool
+        */
+       if (!b->sp_count) {
+               /* FIXME pl left uninitialised if !info->dev */
+               if (!b->pl) {
+                       log_error(INTERNAL_ERROR "device is missing");
+                       dm_pool_destroy(b->tmpmem);
+                       b->failed = 1;
+                       return 0;
+               }
+               b->sp_count = b->pl->pd.pl_subpools;
+               if (!(b->sp_devs =
+                     dm_pool_zalloc(b->tmpmem,
+                                    sizeof(uint32_t) * b->sp_count))) {
+                       log_error("Unable to allocate %d 32-bit uints",
+                                 b->sp_count);
+                       dm_pool_destroy(b->tmpmem);
+                       b->failed = 1;
+                       return 0;
+               }
+       }
+
+       /*
+        * watch out for a pool label with a different subpool
+        * count than the original - give up if it does
+        */
+       if (b->sp_count != b->pl->pd.pl_subpools)
+               return 0;
+
+       _add_pl_to_list(b->head, b->pl);
+
+       if (b->sp_count > b->pl->pd.pl_sp_id && b->sp_devs[b->pl->pd.pl_sp_id] == 0)
+               b->sp_devs[b->pl->pd.pl_sp_id] = b->pl->pd.pl_sp_devs;
 
-       uint32_t sp_count = 0;
-       uint32_t *sp_devs = NULL;
+       return 1;
+}
+
+static int _read_vg_pds(struct _read_pool_pv_baton *b,
+                       struct lvmcache_vginfo *vginfo,
+                       uint32_t *devcount)
+{
        uint32_t i;
 
+       b->sp_count = 0;
+       b->sp_devs = NULL;
+       b->failed = 0;
+       b->pl = NULL;
+
        /* FIXME: maybe should return a different error in memory
         * allocation failure */
-       if (!(tmpmem = dm_pool_create("pool read_vg", 512)))
+       if (!(b->tmpmem = dm_pool_create("pool read_vg", 512)))
                return_0;
 
-       dm_list_iterate_items(info, &vginfo->infos) {
-               if (info->dev &&
-                   !(pl = read_pool_disk(fmt, info->dev, mem, vginfo->vgname)))
-                           break;
-               /*
-                * We need to keep track of the total expected number
-                * of devices per subpool
-                */
-               if (!sp_count) {
-                       /* FIXME pl left uninitialised if !info->dev */
-                       if (!pl) {
-                               log_error(INTERNAL_ERROR "device is missing");
-                               dm_pool_destroy(tmpmem);
-                               return 0;
-                       }
-                       sp_count = pl->pd.pl_subpools;
-                       if (!(sp_devs =
-                             dm_pool_zalloc(tmpmem,
-                                         sizeof(uint32_t) * sp_count))) {
-                               log_error("Unable to allocate %d 32-bit uints",
-                                         sp_count);
-                               dm_pool_destroy(tmpmem);
-                               return 0;
-                       }
-               }
-               /*
-                * watch out for a pool label with a different subpool
-                * count than the original - give up if it does
-                */
-               if (sp_count != pl->pd.pl_subpools)
-                       break;
-
-               _add_pl_to_list(head, pl);
-
-               if (sp_count > pl->pd.pl_sp_id && sp_devs[pl->pd.pl_sp_id] == 0)
-                       sp_devs[pl->pd.pl_sp_id] = pl->pd.pl_sp_devs;
-       }
+       lvmcache_foreach_pv(vginfo, _read_pool_pv, b);
 
        *devcount = 0;
-       for (i = 0; i < sp_count; i++)
-               *devcount += sp_devs[i];
+       for (i = 0; i < b->sp_count; i++)
+               *devcount += b->sp_devs[i];
 
-       dm_pool_destroy(tmpmem);
+       dm_pool_destroy(b->tmpmem);
 
-       if (pl && *pl->pd.pl_pool_name)
+       if (b->pl && *b->pl->pd.pl_pool_name)
                return 1;
 
        return 0;
@@ -311,29 +334,36 @@ int read_pool_pds(const struct format_type *fmt, const char *vg_name,
        uint32_t totaldevs;
        int full_scan = -1;
 
+       struct _read_pool_pv_baton baton;
+
+       baton.vgname = vg_name;
+       baton.mem = mem;
+       baton.fmt = fmt;
+       baton.head = pdhead;
+       baton.empty = 1;
+
        do {
                /*
                 * If the cache scanning doesn't work, this will never work
                 */
-               if (vg_name && (vginfo = vginfo_from_vgname(vg_name, NULL)) &&
-                   vginfo->infos.n) {
-
-                       if (_read_vg_pds(fmt, mem, vginfo, pdhead, &totaldevs)) {
-                               /*
-                                * If we found all the devices we were
-                                * expecting, return success
-                                */
-                               if (dm_list_size(pdhead) == totaldevs)
-                                       return 1;
-
-                               /*
-                                * accept partial pool if we've done a full
-                                * rescan of the cache
-                                */
-                               if (full_scan > 0)
-                                       return 1;
-                       }
+               if (vg_name && (vginfo = lvmcache_vginfo_from_vgname(vg_name, NULL)) &&
+                   _read_vg_pds(&baton, vginfo, &totaldevs) && !baton.empty)
+               {
+                       /*
+                        * If we found all the devices we were expecting, return
+                        * success
+                        */
+                       if (dm_list_size(pdhead) == totaldevs)
+                               return 1;
+
+                       /*
+                        * accept partial pool if we've done a full rescan of
+                        * the cache
+                        */
+                       if (full_scan > 0)
+                               return 1;
                }
+
                /* Failed */
                dm_list_init(pdhead);
 
@@ -355,7 +385,7 @@ struct pool_list *read_pool_disk(const struct format_type *fmt,
 {
        struct pool_list *pl;
 
-       if (!dev_open(dev))
+       if (!dev_open_readonly(dev))
                return_NULL;
 
        if (!(pl = dm_pool_zalloc(mem, sizeof(*pl)))) {
index 730da87f5e01c57bc5094128508fdd2b02257980..04bc4cfb471e86a37d46f45c0a5232a71c373fa4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -98,106 +98,84 @@ static int _check_usp(const char *vgname, struct user_subpool *usp, int sp_count
        return 1;
 }
 
-static struct volume_group *_build_vg_from_pds(struct format_instance
-                                              *fid, struct dm_pool *mem,
-                                              struct dm_list *pds)
+static struct volume_group *_pool_vg_read(struct format_instance *fid,
+                                         const char *vg_name,
+                                         struct metadata_area *mda __attribute__((unused)),
+                                         int single_device __attribute__((unused)))
 {
-       struct dm_pool *smem = fid->fmt->cmd->mem;
-       struct volume_group *vg = NULL;
-       struct user_subpool *usp = NULL;
+       struct volume_group *vg;
+       struct user_subpool *usp;
        int sp_count;
+       DM_LIST_INIT(pds);
 
-       if (!(vg = dm_pool_zalloc(smem, sizeof(*vg)))) {
-               log_error("Unable to allocate volume group structure");
-               return NULL;
-       }
+       /* We can safely ignore the mda passed in */
 
-       vg->cmd = fid->fmt->cmd;
-       vg->vgmem = mem;
-       vg->fid = fid;
-       vg->name = NULL;
-       vg->status = 0;
-       vg->extent_count = 0;
-       vg->pv_count = 0;
-       vg->seqno = 1;
-       vg->system_id = NULL;
-       dm_list_init(&vg->pvs);
-       dm_list_init(&vg->lvs);
-       dm_list_init(&vg->tags);
-       dm_list_init(&vg->removed_pvs);
+       /* Strip dev_dir if present */
+       if (vg_name)
+               vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir);
 
-       if (!import_pool_vg(vg, smem, pds))
+       /* Set vg_name through read_pool_pds() */
+       if (!(vg = alloc_vg("pool_vg_read", fid->fmt->cmd, NULL)))
                return_NULL;
 
-       if (!import_pool_pvs(fid->fmt, vg, smem, pds))
-               return_NULL;
+       /* Read all the pvs in the vg */
+       if (!read_pool_pds(fid->fmt, vg_name, vg->vgmem, &pds))
+               goto_bad;
 
-       if (!import_pool_lvs(vg, smem, pds))
-               return_NULL;
+       vg_set_fid(vg, fid);
+
+       /* Setting pool seqno to 1 because the code always did this,
+        * although we don't think it's needed. */
+       vg->seqno = 1;
+
+       if (!import_pool_vg(vg, vg->vgmem, &pds))
+               goto_bad;
+
+       if (!import_pool_pvs(fid->fmt, vg, vg->vgmem, &pds))
+               goto_bad;
+
+       if (!import_pool_lvs(vg, vg->vgmem, &pds))
+               goto_bad;
 
        /*
         * I need an intermediate subpool structure that contains all the
         * relevant info for this.  Then i can iterate through the subpool
         * structures for checking, and create the segments
         */
-       if (!(usp = _build_usp(pds, mem, &sp_count)))
-               return_NULL;
+       if (!(usp = _build_usp(&pds, vg->vgmem, &sp_count)))
+               goto_bad;
 
        /*
         * check the subpool structures - we can't handle partial VGs in
         * the pool format, so this will error out if we're missing PVs
         */
        if (!_check_usp(vg->name, usp, sp_count))
-               return_NULL;
+               goto_bad;
 
-       if (!import_pool_segments(&vg->lvs, smem, usp, sp_count))
-               return_NULL;
+       if (!import_pool_segments(&vg->lvs, vg->vgmem, usp, sp_count))
+               goto_bad;
 
        return vg;
-}
-
-static struct volume_group *_pool_vg_read(struct format_instance *fid,
-                                    const char *vg_name,
-                                    struct metadata_area *mda __attribute__((unused)))
-{
-       struct dm_pool *mem = dm_pool_create("pool vg_read", VG_MEMPOOL_CHUNK);
-       struct dm_list pds;
-       struct volume_group *vg = NULL;
-
-       dm_list_init(&pds);
 
-       /* We can safely ignore the mda passed in */
-
-       if (!mem)
-               return_NULL;
+bad:
+       release_vg(vg);
 
-       /* Strip dev_dir if present */
-       vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir);
-
-       /* Read all the pvs in the vg */
-       if (!read_pool_pds(fid->fmt, vg_name, mem, &pds))
-               goto_out;
-
-       /* Do the rest of the vg stuff */
-       if (!(vg = _build_vg_from_pds(fid, mem, &pds)))
-               goto_out;
-
-       return vg;
-out:
-       dm_pool_destroy(mem);
        return NULL;
 }
 
+static int _pool_pv_initialise(const struct format_type *fmt __attribute__((unused)),
+                              int64_t label_sector __attribute__((unused)),
+                              uint64_t pe_start __attribute__((unused)),
+                              uint32_t extent_count __attribute__((unused)),
+                              uint32_t extent_size __attribute__((unused)),
+                              unsigned long data_alignment __attribute__((unused)),
+                              unsigned long data_alignment_offset __attribute__((unused)),
+                              struct physical_volume *pv __attribute__((unused)))
+{
+       return 1;
+}
+
 static int _pool_pv_setup(const struct format_type *fmt __attribute__((unused)),
-                         uint64_t pe_start __attribute__((unused)),
-                         uint32_t extent_count __attribute__((unused)),
-                         uint32_t extent_size __attribute__((unused)),
-                         unsigned long data_alignment __attribute__((unused)),
-                         unsigned long data_alignment_offset __attribute__((unused)),
-                         int pvmetadatacopies __attribute__((unused)),
-                         uint64_t pvmetadatasize __attribute__((unused)),
-                         unsigned metadataignore __attribute__((unused)),
-                         struct dm_list *mdas __attribute__((unused)),
                          struct physical_volume *pv __attribute__((unused)),
                          struct volume_group *vg __attribute__((unused)))
 {
@@ -206,7 +184,6 @@ static int _pool_pv_setup(const struct format_type *fmt __attribute__((unused)),
 
 static int _pool_pv_read(const struct format_type *fmt, const char *pv_name,
                         struct physical_volume *pv,
-                        struct dm_list *mdas __attribute__((unused)),
                         int scan_label_only __attribute__((unused)))
 {
        struct dm_pool *mem = dm_pool_create("pool pv_read", 1024);
@@ -249,29 +226,19 @@ static struct metadata_area_ops _metadata_format_pool_ops = {
 /* *INDENT-ON* */
 
 static struct format_instance *_pool_create_instance(const struct format_type *fmt,
-                                               const char *vgname __attribute__((unused)),
-                                               const char *vgid __attribute__((unused)),
-                                               void *private __attribute__((unused)))
+                                                    const struct format_instance_ctx *fic)
 {
        struct format_instance *fid;
        struct metadata_area *mda;
 
-       if (!(fid = dm_pool_zalloc(fmt->cmd->mem, sizeof(*fid)))) {
-               log_error("Unable to allocate format instance structure for "
-                         "pool format");
-               return NULL;
-       }
-
-       fid->fmt = fmt;
-       dm_list_init(&fid->metadata_areas_in_use);
-       dm_list_init(&fid->metadata_areas_ignored);
+       if (!(fid = alloc_fid(fmt, fic)))
+               return_NULL;
 
        /* Define a NULL metadata area */
-       if (!(mda = dm_pool_zalloc(fmt->cmd->mem, sizeof(*mda)))) {
+       if (!(mda = dm_pool_zalloc(fid->mem, sizeof(*mda)))) {
                log_error("Unable to allocate metadata area structure "
                          "for pool format");
-               dm_pool_free(fmt->cmd->mem, fid);
-               return NULL;
+               goto bad;
        }
 
        mda->ops = &_metadata_format_pool_ops;
@@ -280,20 +247,30 @@ static struct format_instance *_pool_create_instance(const struct format_type *f
        dm_list_add(&fid->metadata_areas_in_use, &mda->list);
 
        return fid;
+
+bad:
+       dm_pool_destroy(fid->mem);
+       return NULL;
 }
 
-static void _pool_destroy_instance(struct format_instance *fid __attribute__((unused)))
+static void _pool_destroy_instance(struct format_instance *fid)
 {
+       if (--fid->ref_count <= 1)
+               dm_pool_destroy(fid->mem);
 }
 
 static void _pool_destroy(struct format_type *fmt)
 {
+       if (fmt->orphan_vg)
+               free_orphan_vg(fmt->orphan_vg);
+
        dm_free(fmt);
 }
 
 /* *INDENT-OFF* */
 static struct format_handler _format_pool_ops = {
        .pv_read = _pool_pv_read,
+       .pv_initialise = _pool_pv_initialise,
        .pv_setup = _pool_pv_setup,
        .create_instance = _pool_create_instance,
        .destroy_instance = _pool_destroy_instance,
@@ -309,6 +286,8 @@ struct format_type *init_format(struct cmd_context *cmd)
 #endif
 {
        struct format_type *fmt = dm_malloc(sizeof(*fmt));
+       struct format_instance_ctx fic;
+       struct format_instance *fid;
 
        if (!fmt) {
                log_error("Unable to allocate format type structure for pool "
@@ -324,16 +303,38 @@ struct format_type *init_format(struct cmd_context *cmd)
        fmt->features = 0;
        fmt->private = NULL;
 
+       dm_list_init(&fmt->mda_ops);
+
        if (!(fmt->labeller = pool_labeller_create(fmt))) {
                log_error("Couldn't create pool label handler.");
+               dm_free(fmt);
                return NULL;
        }
 
        if (!(label_register_handler(FMT_POOL_NAME, fmt->labeller))) {
                log_error("Couldn't register pool label handler.");
+               fmt->labeller->ops->destroy(fmt->labeller);
+               dm_free(fmt);
+               return NULL;
+       }
+
+       if (!(fmt->orphan_vg = alloc_vg("pool_orphan", cmd, fmt->orphan_vg_name))) {
+               log_error("Couldn't create pool orphan VG.");
+               dm_free(fmt);
                return NULL;
        }
 
+       fic.type = FMT_INSTANCE_AUX_MDAS;
+       fic.context.vg_ref.vg_name = fmt->orphan_vg_name;
+       fic.context.vg_ref.vg_id = NULL;
+
+       if (!(fid = _pool_create_instance(fmt, &fic))) {
+               _pool_destroy(fmt);
+               return NULL;
+       }
+
+       vg_set_fid(fmt->orphan_vg, fid);
+
        log_very_verbose("Initialised format: %s", fmt->name);
 
        return fmt;
index 788424714e886cac1e349135a137cecda7f48679..480fa1c29c47b4dcc34e0da42d291d24316cb844 100644 (file)
@@ -16,7 +16,6 @@
 #include "lib.h"
 #include "label.h"
 #include "metadata.h"
-#include "lvmcache.h"
 #include "disk_rep.h"
 #include "sptype_names.h"
 #include "lv_alloc.h"
@@ -193,9 +192,9 @@ static int _add_stripe_seg(struct dm_pool *mem,
                                                     "striped")))
                return_0;
 
-       if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur,
+       if (!(seg = alloc_lv_segment(segtype, lv, *le_cur,
                                     area_len * usp->num_devs, 0,
-                                    usp->striping, NULL, usp->num_devs,
+                                    usp->striping, NULL, NULL, usp->num_devs,
                                     area_len, 0, 0, 0, NULL))) {
                log_error("Unable to allocate striped lv_segment structure");
                return 0;
@@ -233,9 +232,9 @@ static int _add_linear_seg(struct dm_pool *mem,
        for (j = 0; j < usp->num_devs; j++) {
                area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
 
-               if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur,
+               if (!(seg = alloc_lv_segment(segtype, lv, *le_cur,
                                             area_len, 0, usp->striping,
-                                            NULL, 1, area_len,
+                                            NULL, NULL, 1, area_len,
                                             POOL_PE_SIZE, 0, 0, NULL))) {
                        log_error("Unable to allocate linear lv_segment "
                                  "structure");
index 2d34e6085b2886eeb1a17740863fe8e6c2851708..7059b9830aa2d580db067d5a503ac7a2834de2fa 100644 (file)
@@ -16,7 +16,6 @@
 #include "lib.h"
 #include "label.h"
 #include "metadata.h"
-#include "xlate.h"
 #include "disk_rep.h"
 #include "pool_label.h"
 
index 43425dc30eb99c462ef75c18ea9ad46922ce2a42..18fe577065c4dc346b854d60aa8bbfd7da9adc10 100644 (file)
@@ -25,7 +25,6 @@
 #include <dirent.h>
 #include <unistd.h>
 #include <sys/stat.h>
-#include <sys/file.h>
 #include <fcntl.h>
 #include <time.h>
 
@@ -300,16 +299,19 @@ static void _display_archive(struct cmd_context *cmd, struct archive_file *af)
 {
        struct volume_group *vg = NULL;
        struct format_instance *tf;
+       struct format_instance_ctx fic;
+       struct text_context tc = {.path_live = af->path,
+                                 .path_edit = NULL,
+                                 .desc = NULL};
        time_t when;
        char *desc;
-       void *context;
 
        log_print(" ");
        log_print("File:\t\t%s", af->path);
 
-       if (!(context = create_text_context(cmd, af->path, NULL)) ||
-           !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
-                                                        NULL, context))) {
+       fic.type = FMT_INSTANCE_PRIVATE_MDAS;
+       fic.context.private = &tc;
+       if (!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, &fic))) {
                log_error("Couldn't create text instance object.");
                return;
        }
@@ -329,8 +331,7 @@ static void _display_archive(struct cmd_context *cmd, struct archive_file *af)
        log_print("Description:\t%s", desc ? : "<No description>");
        log_print("Backup Time:\t%s", ctime(&when));
 
-       free_vg(vg);
-       tf->fmt->ops->destroy_instance(tf);
+       release_vg(vg);
 }
 
 int archive_list(struct cmd_context *cmd, const char *dir, const char *vgname)
index ef85c6cbfae32a7cd66bb7b946caf0fc7bc936a4..ccefb4cea032f03f0a57c60b19de94f90c3df370 100644 (file)
@@ -16,7 +16,6 @@
 #include "lib.h"
 #include "archiver.h"
 #include "format-text.h"
-#include "lvm-file.h"
 #include "lvm-string.h"
 #include "lvmcache.h"
 #include "toolcontext.h"
@@ -69,8 +68,7 @@ void archive_exit(struct cmd_context *cmd)
 {
        if (!cmd->archive_params)
                return;
-       if (cmd->archive_params->dir)
-               dm_free(cmd->archive_params->dir);
+       dm_free(cmd->archive_params->dir);
        memset(cmd->archive_params, 0, sizeof(*cmd->archive_params));
 }
 
@@ -84,13 +82,16 @@ static char *_build_desc(struct dm_pool *mem, const char *line, int before)
        size_t len = strlen(line) + 32;
        char *buffer;
 
-       if (!(buffer = dm_pool_zalloc(mem, strlen(line) + 32)))
-               return_NULL;
+       if (!(buffer = dm_pool_alloc(mem, len))) {
+               log_error("Failed to allocate desc.");
+               return NULL;
+       }
 
-       if (snprintf(buffer, len,
-                    "Created %s executing '%s'",
-                    before ? "*before*" : "*after*", line) < 0)
-               return_NULL;
+       if (dm_snprintf(buffer, len, "Created %s executing '%s'",
+                       before ? "*before*" : "*after*", line) < 0) {
+               log_error("Failed to build desc.");
+               return NULL;
+       }
 
        return buffer;
 }
@@ -183,8 +184,7 @@ void backup_exit(struct cmd_context *cmd)
 {
        if (!cmd->backup_params)
                return;
-       if (cmd->backup_params->dir)
-               dm_free(cmd->backup_params->dir);
+       dm_free(cmd->backup_params->dir);
        memset(cmd->backup_params, 0, sizeof(*cmd->backup_params));
 }
 
@@ -219,7 +219,7 @@ int backup_locally(struct volume_group *vg)
        }
 
        if (test_mode()) {
-               log_verbose("Test mode: Skipping volume group backup.");
+               log_verbose("Test mode: Skipping backup of volume group.");
                return 1;
        }
 
@@ -243,7 +243,8 @@ int backup_locally(struct volume_group *vg)
 int backup(struct volume_group *vg)
 {
        if (vg_is_clustered(vg))
-               remote_backup_metadata(vg);
+               if (!remote_backup_metadata(vg))
+                       stack;
 
        return backup_locally(vg);
 }
@@ -261,7 +262,9 @@ int backup_remove(struct cmd_context *cmd, const char *vg_name)
        /*
         * Let this fail silently.
         */
-       unlink(path);
+       if (unlink(path))
+               log_sys_debug("unlink", path);
+
        return 1;
 }
 
@@ -270,24 +273,28 @@ struct volume_group *backup_read_vg(struct cmd_context *cmd,
 {
        struct volume_group *vg = NULL;
        struct format_instance *tf;
+       struct format_instance_ctx fic;
+       struct text_context tc = {.path_live = file,
+                                 .path_edit = NULL,
+                                 .desc = cmd->cmd_line};
        struct metadata_area *mda;
-       void *context;
 
-       if (!(context = create_text_context(cmd, file,
-                                           cmd->cmd_line)) ||
-           !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
-                                                        NULL, context))) {
+       fic.type = FMT_INSTANCE_PRIVATE_MDAS;
+       fic.context.private = &tc;
+       if (!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, &fic))) {
                log_error("Couldn't create text format object.");
                return NULL;
        }
 
        dm_list_iterate_items(mda, &tf->metadata_areas_in_use) {
-               if (!(vg = mda->ops->vg_read(tf, vg_name, mda)))
+               if (!(vg = mda->ops->vg_read(tf, vg_name, mda, 0)))
                        stack;
                break;
        }
 
-       tf->fmt->ops->destroy_instance(tf);
+       if (!vg)
+               tf->fmt->ops->destroy_instance(tf);
+
        return vg;
 }
 
@@ -295,8 +302,9 @@ struct volume_group *backup_read_vg(struct cmd_context *cmd,
 int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg)
 {
        struct pv_list *pvl;
-       struct physical_volume *pv;
-       struct lvmcache_info *info;
+       struct format_instance *fid;
+       struct format_instance_ctx fic;
+       uint32_t tmp;
 
        /*
         * FIXME: Check that the PVs referenced in the backup are
@@ -304,11 +312,14 @@ int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg)
         */
 
        /* Attempt to write out using currently active format */
-       if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg->name,
-                                                      NULL, NULL))) {
+       fic.type = FMT_INSTANCE_AUX_MDAS;
+       fic.context.vg_ref.vg_name = vg->name;
+       fic.context.vg_ref.vg_id = NULL;
+       if (!(fid = cmd->fmt->ops->create_instance(cmd->fmt, &fic))) {
                log_error("Failed to allocate format instance");
                return 0;
        }
+       vg_set_fid(vg, fid);
 
        /*
         * Setting vg->old_name to a blank value will explicitly
@@ -318,25 +329,14 @@ int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg)
 
        /* Add any metadata areas on the PVs */
        dm_list_iterate_items(pvl, &vg->pvs) {
-               pv = pvl->pv;
-               if (!(info = info_from_pvid(pv->dev->pvid, 0))) {
-                       log_error("PV %s missing from cache",
-                                 pv_dev_name(pv));
-                       return 0;
-               }
-               if (cmd->fmt != info->fmt) {
-                       log_error("PV %s is a different format (seqno %s)",
-                                 pv_dev_name(pv), info->fmt->name);
-                       return 0;
-               }
-               if (!vg->fid->fmt->ops->
-                   pv_setup(vg->fid->fmt, UINT64_C(0), 0, 0, 0, 0, 0UL,
-                            UINT64_C(0), 0,
-                            &vg->fid->metadata_areas_in_use, pv, vg)) {
+               tmp = vg->extent_size;
+               vg->extent_size = 0;
+               if (!vg->fid->fmt->ops->pv_setup(vg->fid->fmt, pvl->pv, vg)) {
                        log_error("Format-specific setup for %s failed",
-                                 pv_dev_name(pv));
+                                 pv_dev_name(pvl->pv));
                        return 0;
                }
+               vg->extent_size = tmp;
        }
 
        if (!vg_write(vg) || !vg_commit(vg))
@@ -351,6 +351,7 @@ int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
 {
        struct volume_group *vg;
        int missing_pvs, r = 0;
+       const struct lv_list *lvl;
 
        /*
         * Read in the volume group from the text file.
@@ -358,6 +359,16 @@ int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
        if (!(vg = backup_read_vg(cmd, vg_name, file)))
                return_0;
 
+       /* FIXME: Restore support is missing for now */
+       dm_list_iterate_items(lvl, &vg->lvs)
+               if (lv_is_thin_type(lvl->lv)) {
+                       log_error("Cannot restore Volume Group %s with "
+                                 "thin logical volumes. "
+                                 "(not yet supported).", vg->name);
+                       r = 0;
+                       goto out;
+               }
+
        missing_pvs = vg_missing_pv_count(vg);
        if (missing_pvs == 0)
                r = backup_restore_vg(cmd, vg);
@@ -365,7 +376,8 @@ int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
                log_error("Cannot restore Volume Group %s with %i PVs "
                          "marked as missing.", vg->name, missing_pvs);
 
-       free_vg(vg);
+out:
+       release_vg(vg);
        return r;
 }
 
@@ -386,23 +398,27 @@ int backup_to_file(const char *file, const char *desc, struct volume_group *vg)
 {
        int r = 0;
        struct format_instance *tf;
+       struct format_instance_ctx fic;
+       struct text_context tc = {.path_live = file,
+                                 .path_edit = NULL,
+                                 .desc = desc};
        struct metadata_area *mda;
-       void *context;
        struct cmd_context *cmd;
 
        cmd = vg->cmd;
 
        log_verbose("Creating volume group backup \"%s\" (seqno %u).", file, vg->seqno);
 
-       if (!(context = create_text_context(cmd, file, desc)) ||
-           !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
-                                                        NULL, context))) {
+       fic.type = FMT_INSTANCE_PRIVATE_MDAS;
+       fic.context.private = &tc;
+       if (!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, &fic))) {
                log_error("Couldn't create backup object.");
                return 0;
        }
 
        if (!dm_list_size(&tf->metadata_areas_in_use)) {
                log_error(INTERNAL_ERROR "No in use metadata areas to write.");
+               tf->fmt->ops->destroy_instance(tf);
                return 0;
        }
 
@@ -446,15 +462,18 @@ void check_current_backup(struct volume_group *vg)
            (vg->seqno == vg_backup->seqno) &&
            (id_equal(&vg->id, &vg_backup->id))) {
                log_suppress(old_suppress);
-               free_vg(vg_backup);
+               release_vg(vg_backup);
                return;
        }
        log_suppress(old_suppress);
 
        if (vg_backup) {
-               archive(vg_backup);
-               free_vg(vg_backup);
+               if (!archive(vg_backup))
+                       stack;
+               release_vg(vg_backup);
        }
-       archive(vg);
-       backup_locally(vg);
+       if (!archive(vg))
+               stack;
+       if (!backup_locally(vg))
+               stack;
 }
index 8ddfa854f9116d4c56acf372b0c628a372a47fb2..70c1aa609bece21e033c2af036cbdc20d118f226 100644 (file)
@@ -27,6 +27,7 @@
 #include <sys/utsname.h>
 
 struct formatter;
+__attribute__((format(printf, 3, 0)))
 typedef int (*out_with_comment_fn) (struct formatter * f, const char *comment,
                                    const char *fmt, va_list ap);
 typedef int (*nl_fn) (struct formatter * f);
@@ -147,6 +148,7 @@ static int _nl_raw(struct formatter *f)
 }
 
 #define COMMENT_TAB 6
+__attribute__((format(printf, 3, 0)))
 static int _out_with_comment_file(struct formatter *f, const char *comment,
                                  const char *fmt, va_list ap)
 {
@@ -182,6 +184,7 @@ static int _out_with_comment_file(struct formatter *f, const char *comment,
        return 1;
 }
 
+__attribute__((format(printf, 3, 0)))
 static int _out_with_comment_raw(struct formatter *f,
                                 const char *comment __attribute__((unused)),
                                 const char *fmt, va_list ap)
@@ -316,9 +319,9 @@ static int _out_line(const char *line, void *_f) {
        return out_text(f, "%s", line);
 }
 
-int out_config_node(struct formatter *f, const struct config_node *cn)
+int out_config_node(struct formatter *f, const struct dm_config_node *cn)
 {
-       return write_config_node(cn, _out_line, f);
+       return dm_config_write_node(cn, _out_line, f);
 }
 
 static int _print_header(struct formatter *f,
@@ -334,12 +337,12 @@ static int _print_header(struct formatter *f,
        outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE);
        outnl(f);
 
-       if (!(buf = alloca(escaped_len(desc)))) {
+       if (!(buf = alloca(dm_escaped_len(desc)))) {
                log_error("temporary stack allocation for description"
                          "string failed");
                return 0;
        }
-       outf(f, "description = \"%s\"", escape_double_quotes(buf, desc));
+       outf(f, "description = \"%s\"", dm_escape_double_quotes(buf, desc));
        outnl(f);
        outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
             _utsname.sysname, _utsname.nodename, _utsname.release,
@@ -392,6 +395,9 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
 
        outf(f, "seqno = %u", vg->seqno);
 
+       if (vg->fid && vg->fid->fmt)
+               outf(f, "format = \"%s\" # informational", vg->fid->fmt->name);
+
        if (!_print_flag_config(f, vg->status, VG_FLAGS))
                return_0;
 
@@ -462,14 +468,14 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
 
                outf(f, "id = \"%s\"", buffer);
 
-               if (!(buf = alloca(escaped_len(pv_dev_name(pv))))) {
+               if (!(buf = alloca(dm_escaped_len(pv_dev_name(pv))))) {
                        log_error("temporary stack allocation for device name"
                                  "string failed");
                        return 0;
                }
 
                outhint(f, "device = \"%s\"",
-                       escape_double_quotes(buf, pv_dev_name(pv)));
+                       dm_escape_double_quotes(buf, pv_dev_name(pv)));
                outnl(f);
 
                if (!_print_flag_config(f, pv->status, PV_FLAGS))
@@ -541,10 +547,25 @@ int out_areas(struct formatter *f, const struct lv_segment *seg,
                             (s == seg->area_count - 1) ? "" : ",");
                        break;
                case AREA_LV:
-                       outf(f, "\"%s\", %u%s",
-                            seg_lv(seg, s)->name,
-                            seg_le(seg, s),
+                       if (!(seg->status & RAID)) {
+                               outf(f, "\"%s\", %u%s",
+                                    seg_lv(seg, s)->name,
+                                    seg_le(seg, s),
+                                    (s == seg->area_count - 1) ? "" : ",");
+                               continue;
+                       }
+
+                       /* RAID devices are laid-out in metadata/data pairs */
+                       if (!(seg_lv(seg, s)->status & RAID_IMAGE) ||
+                           !(seg_metalv(seg, s)->status & RAID_META)) {
+                               log_error("RAID segment has non-RAID areas");
+                               return 0;
+                       }
+
+                       outf(f, "\"%s\", \"%s\"%s",
+                            seg_metalv(seg, s)->name, seg_lv(seg, s)->name,
                             (s == seg->area_count - 1) ? "" : ",");
+
                        break;
                case AREA_UNASSIGNED:
                        return 0;
@@ -561,6 +582,8 @@ static int _print_lv(struct formatter *f, struct logical_volume *lv)
        struct lv_segment *seg;
        char buffer[4096];
        int seg_count;
+       struct tm *local_tm;
+       time_t ts;
 
        outnl(f);
        outf(f, "%s {", lv->name);
@@ -578,6 +601,19 @@ static int _print_lv(struct formatter *f, struct logical_volume *lv)
        if (!_out_tags(f, &lv->tags))
                return_0;
 
+       if (lv->timestamp) {
+               ts = (time_t)lv->timestamp;
+               strncpy(buffer, "# ", sizeof(buffer));
+               if (!(local_tm = localtime(&ts)) ||
+                   !strftime(buffer + 2, sizeof(buffer) - 2,
+                             "%Y-%m-%d %T %z", local_tm))
+                       buffer[0] = 0;
+
+               outf(f, "creation_host = \"%s\"", lv->hostname);
+               outfc(f, buffer, "creation_time = %" PRIu64,
+                     lv->timestamp);
+       }
+
        if (lv->alloc != ALLOC_INHERIT)
                outf(f, "allocation_policy = \"%s\"",
                     get_alloc_string(lv->alloc));
@@ -724,11 +760,15 @@ static int _text_vg_export(struct formatter *f,
        r = 1;
 
       out:
-       if (f->mem)
+       if (f->mem) {
                dm_pool_destroy(f->mem);
+               f->mem = NULL;
+       }
 
-       if (f->pv_names)
+       if (f->pv_names) {
                dm_hash_destroy(f->pv_names);
+               f->pv_names = NULL;
+       }
 
        return r;
 }
@@ -757,10 +797,10 @@ int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp)
 }
 
 /* Returns amount of buffer used incl. terminating NUL */
-int text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf)
+size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf)
 {
        struct formatter *f;
-       int r = 0;
+       size_t r = 0;
 
        _init();
 
@@ -791,7 +831,7 @@ int text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf)
        return r;
 }
 
-int export_vg_to_buffer(struct volume_group *vg, char **buf)
+size_t export_vg_to_buffer(struct volume_group *vg, char **buf)
 {
        return text_vg_export_raw(vg, "", buf);
 }
index 1d2a6110bb4e5c1913e1924964a23b70b736817e..dbca8c981e7a16affa8860f4b00265b7dd8f4de8 100644 (file)
@@ -45,6 +45,7 @@ static const struct flag _pv_flags[] = {
        {ALLOCATABLE_PV, "ALLOCATABLE", STATUS_FLAG},
        {EXPORTED_VG, "EXPORTED", STATUS_FLAG},
        {MISSING_PV, "MISSING", COMPATIBLE_FLAG},
+       {UNLABELLED_PV, NULL, 0},
        {0, NULL, 0}
 };
 
@@ -55,20 +56,27 @@ static const struct flag _lv_flags[] = {
        {VISIBLE_LV, "VISIBLE", STATUS_FLAG},
        {PVMOVE, "PVMOVE", STATUS_FLAG},
        {LOCKED, "LOCKED", STATUS_FLAG},
-       {MIRROR_NOTSYNCED, "NOTSYNCED", STATUS_FLAG},
+       {LV_NOTSYNCED, "NOTSYNCED", STATUS_FLAG},
+       {LV_REBUILD, "REBUILD", STATUS_FLAG},
+       {RAID, NULL, 0},
+       {RAID_META, NULL, 0},
+       {RAID_IMAGE, NULL, 0},
        {MIRROR_IMAGE, NULL, 0},
        {MIRROR_LOG, NULL, 0},
        {MIRRORED, NULL, 0},
        {VIRTUAL, NULL, 0},
        {SNAPSHOT, NULL, 0},
        {MERGING, NULL, 0},
-       {ACTIVATE_EXCL, NULL, 0},
        {CONVERTING, NULL, 0},
        {PARTIAL_LV, NULL, 0},
        {POSTORDER_FLAG, NULL, 0},
        {VIRTUAL_ORIGIN, NULL, 0},
        {REPLICATOR, NULL, 0},
        {REPLICATOR_LOG, NULL, 0},
+       {THIN_VOLUME, NULL, 0},
+       {THIN_POOL, NULL, 0},
+       {THIN_POOL_DATA, NULL, 0},
+       {THIN_POOL_METADATA, NULL, 0},
        {0, NULL, 0}
 };
 
@@ -138,7 +146,7 @@ int print_flags(uint64_t status, int type, char *buffer, size_t size)
        return 1;
 }
 
-int read_flags(uint64_t *status, int type, const struct config_value *cv)
+int read_flags(uint64_t *status, int type, const struct dm_config_value *cv)
 {
        int f;
        uint64_t s = UINT64_C(0);
@@ -147,11 +155,11 @@ int read_flags(uint64_t *status, int type, const struct config_value *cv)
        if (!(flags = _get_flags(type)))
                return_0;
 
-       if (cv->type == CFG_EMPTY_ARRAY)
+       if (cv->type == DM_CFG_EMPTY_ARRAY)
                goto out;
 
        while (cv) {
-               if (cv->type != CFG_STRING) {
+               if (cv->type != DM_CFG_STRING) {
                        log_error("Status value is not a string.");
                        return 0;
                }
index c186757eeea823fb243b11a79cbc07b4843595d7..b562cfa2b2e8777fcb25dcb4ef3bce012dac5015 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
 #include "crc.h"
 #include "xlate.h"
 #include "label.h"
-#include "memlock.h"
 #include "lvmcache.h"
+#include "lvmetad.h"
 
 #include <unistd.h>
-#include <sys/file.h>
 #include <sys/param.h>
 #include <limits.h>
 #include <dirent.h>
 #include <ctype.h>
 
-static struct format_instance *_text_create_text_instance(const struct format_type
-                                                    *fmt, const char *vgname,
-                                                    const char *vgid,
-                                                    void *context);
+static struct format_instance *_text_create_text_instance(const struct format_type *fmt,
+                                                         const struct format_instance_ctx *fic);
 
 struct text_fid_context {
        char *raw_metadata_buf;
@@ -57,12 +54,6 @@ struct raw_list {
        struct device_area dev_area;
 };
 
-struct text_context {
-       char *path_live;        /* Path to file holding live metadata */
-       char *path_edit;        /* Path to file holding edited metadata */
-       char *desc;             /* Description placed inside file */
-};
-
 int rlocn_is_ignored(const struct raw_locn *rlocn)
 {
        return (rlocn->flags & RAW_LOCN_IGNORED ? 1 : 0);
@@ -135,6 +126,12 @@ static unsigned _mda_locns_match_raw(struct metadata_area *mda1,
        return 0;
 }
 
+static struct device *_mda_get_device_raw(struct metadata_area *mda)
+{
+       struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
+       return mdac->area.dev;
+}
+
 /*
  * For circular region between region_start and region_start + region_size,
  * back up one SECTOR_SIZE from 'region_ptr' and return the value.
@@ -188,7 +185,7 @@ static int _pv_analyze_mda_raw (const struct format_type * fmt,
                  PRIu64, mdac->area.start, mdac->area.size);
        area = &mdac->area;
 
-       if (!dev_open(area->dev))
+       if (!dev_open_readonly(area->dev))
                return_0;
 
        if (!(mdah = raw_read_mda_header(fmt, area)))
@@ -225,10 +222,10 @@ static int _pv_analyze_mda_raw (const struct format_type * fmt,
                 * area->start to area->start+area->size is not used.
                 * Only ~32KB seems to contain valid metadata records
                 * (LVM2 format - format_text).  As a result, I end up with
-                * "maybe_config_section" returning true when there's no valid
+                * "dm_config_maybe_section" returning true when there's no valid
                 * metadata in a sector (sectors with all nulls).
                 */
-               if (!(buf = dm_pool_alloc(fmt->cmd->mem, size + size2)))
+               if (!(buf = dm_malloc(size + size2)))
                        goto_out;
 
                if (!dev_read_circular(area->dev, offset, size,
@@ -238,7 +235,7 @@ static int _pv_analyze_mda_raw (const struct format_type * fmt,
                /*
                 * FIXME: We could add more sophisticated metadata detection
                 */
-               if (maybe_config_section(buf, size + size2)) {
+               if (dm_config_maybe_section(buf, size + size2)) {
                        /* FIXME: Validate region, pull out timestamp?, etc */
                        /* FIXME: Do something with this region */
                        log_verbose ("Found LVM2 metadata record at "
@@ -263,14 +260,14 @@ static int _pv_analyze_mda_raw (const struct format_type * fmt,
                                size += SECTOR_SIZE;
                        }
                }
-               dm_pool_free(fmt->cmd->mem, buf);
+               dm_free(buf);
                buf = NULL;
        }
 
        r = 1;
  out:
        if (buf)
-               dm_pool_free(fmt->cmd->mem, buf);
+               dm_free(buf);
        if (!dev_close(area->dev))
                stack;
        return r;
@@ -434,7 +431,7 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
                          "not match expected name %s.", vgname);
 
       bad:
-       if ((info = info_from_pvid(dev_area->dev->pvid, 0)))
+       if ((info = lvmcache_info_from_pvid(dev_area->dev->pvid, 0)))
                lvmcache_update_vgname_and_id(info, FMT_TEXT_ORPHAN_VG_NAME,
                                              FMT_TEXT_ORPHAN_VG_NAME, 0, NULL);
 
@@ -466,7 +463,7 @@ static int _raw_holds_vgname(struct format_instance *fid,
        int noprecommit = 0;
        struct mda_header *mdah;
 
-       if (!dev_open(dev_area->dev))
+       if (!dev_open_readonly(dev_area->dev))
                return_0;
 
        if (!(mdah = raw_read_mda_header(fid->fmt, dev_area)))
@@ -484,7 +481,8 @@ static int _raw_holds_vgname(struct format_instance *fid,
 static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
                                              const char *vgname,
                                              struct device_area *area,
-                                             int precommitted)
+                                             int precommitted,
+                                             int single_device)
 {
        struct volume_group *vg = NULL;
        struct raw_locn *rlocn;
@@ -511,7 +509,7 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
        }
 
        /* FIXME 64-bit */
-       if (!(vg = text_vg_import_fd(fid, NULL, area->dev,
+       if (!(vg = text_vg_import_fd(fid, NULL, single_device, area->dev, 
                                     (off_t) (area->start + rlocn->offset),
                                     (uint32_t) (rlocn->size - wrap),
                                     (off_t) (area->start + MDA_HEADER_SIZE),
@@ -532,15 +530,16 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
 
 static struct volume_group *_vg_read_raw(struct format_instance *fid,
                                         const char *vgname,
-                                        struct metadata_area *mda)
+                                        struct metadata_area *mda,
+                                        int single_device)
 {
        struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
        struct volume_group *vg;
 
-       if (!dev_open(mdac->area.dev))
+       if (!dev_open_readonly(mdac->area.dev))
                return_NULL;
 
-       vg = _vg_read_raw_area(fid, vgname, &mdac->area, 0);
+       vg = _vg_read_raw_area(fid, vgname, &mdac->area, 0, single_device);
 
        if (!dev_close(mdac->area.dev))
                stack;
@@ -555,10 +554,10 @@ static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
        struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
        struct volume_group *vg;
 
-       if (!dev_open(mdac->area.dev))
+       if (!dev_open_readonly(mdac->area.dev))
                return_NULL;
 
-       vg = _vg_read_raw_area(fid, vgname, &mdac->area, 1);
+       vg = _vg_read_raw_area(fid, vgname, &mdac->area, 1, 0);
 
        if (!dev_close(mdac->area.dev))
                stack;
@@ -740,6 +739,7 @@ static int _vg_commit_raw_rlocn(struct format_instance *fid,
                          dev_name(mdac->area.dev), mdac->area.start);
 
        rlocn_set_ignored(mdah->raw_locns, mda_is_ignored(mda));
+
        if (!_raw_write_mda_header(fid->fmt, mdac->area.dev, mdac->area.start,
                                   mdah)) {
                dm_pool_free(fid->fmt->cmd->mem, mdah);
@@ -857,7 +857,7 @@ static struct volume_group *_vg_read_file_name(struct format_instance *fid,
         * check that it contains the correct volume group.
         */
        if (vgname && strcmp(vgname, vg->name)) {
-               free_vg(vg);
+               release_vg(vg);
                log_error("'%s' does not contain volume group '%s'.",
                          read_path, vgname);
                return NULL;
@@ -869,7 +869,8 @@ static struct volume_group *_vg_read_file_name(struct format_instance *fid,
 
 static struct volume_group *_vg_read_file(struct format_instance *fid,
                                          const char *vgname,
-                                         struct metadata_area *mda)
+                                         struct metadata_area *mda,
+                                         int single_device __attribute__((unused)))
 {
        struct text_context *tc = (struct text_context *) mda->metadata_locn;
 
@@ -990,7 +991,7 @@ static int _vg_commit_file(struct format_instance *fid, struct volume_group *vg,
                           struct metadata_area *mda)
 {
        struct text_context *tc = (struct text_context *) mda->metadata_locn;
-       char *slash;
+       const char *slash;
        char new_name[PATH_MAX];
        size_t len;
 
@@ -1054,6 +1055,7 @@ static int _scan_file(const struct format_type *fmt, const char *vgname)
        DIR *d;
        struct volume_group *vg;
        struct format_instance *fid;
+       struct format_instance_ctx fic;
        char path[PATH_MAX];
        char *scanned_vgname;
 
@@ -1084,13 +1086,15 @@ static int _scan_file(const struct format_type *fmt, const char *vgname)
                                }
 
                                /* FIXME stat file to see if it's changed */
-                               fid = _text_create_text_instance(fmt, NULL, NULL,
-                                                           NULL);
+                               /* FIXME: Check this fid is OK! */
+                               fic.type = FMT_INSTANCE_PRIVATE_MDAS;
+                               fic.context.private = NULL;
+                               fid = _text_create_text_instance(fmt, &fic);
                                if ((vg = _vg_read_file_name(fid, scanned_vgname,
                                                             path))) {
                                        /* FIXME Store creation host in vg */
                                        lvmcache_update_vg(vg, 0);
-                                       free_vg(vg);
+                                       release_vg(vg);
                                }
                        }
 
@@ -1219,7 +1223,7 @@ static int _scan_raw(const struct format_type *fmt, const char *vgname __attribu
 
        dm_list_iterate_items(rl, raw_list) {
                /* FIXME We're reading mdah twice here... */
-               if (!dev_open(rl->dev_area.dev)) {
+               if (!dev_open_readonly(rl->dev_area.dev)) {
                        stack;
                        continue;
                }
@@ -1232,7 +1236,7 @@ static int _scan_raw(const struct format_type *fmt, const char *vgname __attribu
                if ((scanned_vgname = vgname_from_mda(fmt, mdah,
                                              &rl->dev_area, &vgid, &vgstatus,
                                              NULL, NULL))) {
-                       vg = _vg_read_raw_area(&fid, scanned_vgname, &rl->dev_area, 0);
+                       vg = _vg_read_raw_area(&fid, scanned_vgname, &rl->dev_area, 0, 0);
                        if (vg)
                                lvmcache_update_vg(vg, 0);
 
@@ -1250,306 +1254,121 @@ static int _text_scan(const struct format_type *fmt, const char *vgname)
        return (_scan_file(fmt, vgname) & _scan_raw(fmt, vgname));
 }
 
-/* For orphan, creates new mdas according to policy.
-   Always have an mda between end-of-label and pe_align() boundary */
-static int _mda_setup(const struct format_type *fmt,
-                     uint64_t pe_start, uint64_t pe_end,
-                     int pvmetadatacopies, uint64_t pvmetadatasize,
-                     unsigned metadataignore, struct dm_list *mdas,
-                     struct physical_volume *pv,
-                     struct volume_group *vg __attribute__((unused)))
-{
-       uint64_t mda_adjustment, disk_size, alignment, alignment_offset;
-       uint64_t start1, mda_size1;     /* First area - start of disk */
-       uint64_t start2, mda_size2;     /* Second area - end of disk */
-       uint64_t wipe_size = 8 << SECTOR_SHIFT;
-       size_t pagesize = lvm_getpagesize();
-
-       if (!pvmetadatacopies)
-               return 1;
-
-       alignment = pv->pe_align << SECTOR_SHIFT;
-       alignment_offset = pv->pe_align_offset << SECTOR_SHIFT;
-       disk_size = pv->size << SECTOR_SHIFT;
-       pe_start <<= SECTOR_SHIFT;
-       pe_end <<= SECTOR_SHIFT;
-
-       if (pe_end > disk_size) {
-               log_error("Physical extents end beyond end of device %s!",
-                         pv_dev_name(pv));
-               return 0;
-       }
-
-       /* Requested metadatasize */
-       mda_size1 = pvmetadatasize << SECTOR_SHIFT;
-
-       /* Place mda straight after label area at start of disk */
-       start1 = LABEL_SCAN_SIZE;
-
-       /* Unless the space available is tiny, round to PAGE_SIZE boundary */
-       if ((!pe_start && !pe_end) ||
-           ((pe_start > start1) && (pe_start - start1 >= MDA_SIZE_MIN))) {
-               mda_adjustment = start1 % pagesize;
-               if (mda_adjustment)
-                       start1 += (pagesize - mda_adjustment);
-       }
-
-       /* Round up to pe_align boundary */
-       mda_adjustment = (mda_size1 + start1) % alignment;
-       if (mda_adjustment) {
-               mda_size1 += (alignment - mda_adjustment);
-               /* Revert if it's now too large */
-               if (start1 + mda_size1 > disk_size)
-                       mda_size1 -= (alignment - mda_adjustment);
-       }
-
-       /* Add pe_align_offset if on pe_align boundary */
-       if (alignment_offset &&
-           (((start1 + mda_size1) % alignment) == 0)) {
-               mda_size1 += alignment_offset;
-               /* Revert if it's now too large */
-               if (start1 + mda_size1 > disk_size)
-                       mda_size1 -= alignment_offset;
-       }
-
-       /* Ensure it's not going to be bigger than the disk! */
-       if (start1 + mda_size1 > disk_size) {
-               log_warn("WARNING: metadata area fills disk leaving no "
-                        "space for data on %s.", pv_dev_name(pv));
-               /* Leave some free space for rounding */
-               /* Avoid empty data area as could cause tools problems */
-               mda_size1 = disk_size - start1 - alignment * 2;
-               if (start1 + mda_size1 > disk_size) {
-                       log_error("Insufficient space for first mda on %s",
-                                 pv_dev_name(pv));
-                       return 0;
-               }
-               /* Round up to pe_align boundary */
-               mda_adjustment = (mda_size1 + start1) % alignment;
-               if (mda_adjustment)
-                       mda_size1 += (alignment - mda_adjustment);
-               /* Only have 1 mda in this case */
-               pvmetadatacopies = 1;
-       }
-
-       /* If we already have PEs, avoid overlap */
-       if (pe_start || pe_end) {
-               if (pe_start <= start1)
-                       mda_size1 = 0;
-               else if (start1 + mda_size1 > pe_start)
-                       mda_size1 = pe_start - start1;
-       }
-
-       /* FIXME If creating new mdas, wipe them! */
-       if (mda_size1) {
-               if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start1,
-                            mda_size1, metadataignore))
-                       return 0;
-
-               if (!dev_set((struct device *) pv->dev, start1,
-                            (size_t) (mda_size1 >
-                                      wipe_size ? : mda_size1), 0)) {
-                       log_error("Failed to wipe new metadata area");
-                       return 0;
-               }
-
-               if (pvmetadatacopies == 1)
-                       return 1;
-       } else
-               start1 = 0;
-
-       /* A second copy at end of disk */
-       mda_size2 = pvmetadatasize << SECTOR_SHIFT;
-
-       /* Ensure it's not going to be bigger than the disk! */
-       if (mda_size2 > disk_size)
-               mda_size2 = disk_size - start1 - mda_size1;
+struct _write_single_mda_baton {
+       const struct format_type *fmt;
+       struct physical_volume *pv;
+};
 
-       mda_adjustment = (disk_size - mda_size2) % alignment;
-       if (mda_adjustment)
-               mda_size2 += mda_adjustment;
+static int _write_single_mda(struct metadata_area *mda, void *baton)
+{
+       struct _write_single_mda_baton *p = baton;
+       struct mda_context *mdac;
 
-       start2 = disk_size - mda_size2;
+       char buf[MDA_HEADER_SIZE] __attribute__((aligned(8))) = { 0 };
+       struct mda_header *mdah = (struct mda_header *) buf;
 
-       /* If we already have PEs, avoid overlap */
-       if (pe_start || pe_end) {
-               if (start2 < pe_end) {
-                       mda_size2 -= (pe_end - start2);
-                       start2 = pe_end;
-               }
-       }
+       mdac = mda->metadata_locn;
+       mdah->size = mdac->area.size;
+       rlocn_set_ignored(mdah->raw_locns, mda_is_ignored(mda));
 
-       /* If we already have a first mda, avoid overlap */
-       if (mda_size1) {
-               if (start2 < start1 + mda_size1) {
-                       mda_size2 -= (start1 + mda_size1 - start2);
-                       start2 = start1 + mda_size1;
-               }
-               /* No room for any PEs here now! */
+       if (!_raw_write_mda_header(p->fmt, mdac->area.dev,
+                                  mdac->area.start, mdah)) {
+               if (!dev_close(p->pv->dev))
+                       stack;
+               return_0;
        }
-
-       if (mda_size2) {
-               if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start2,
-                            mda_size2, metadataignore)) return 0;
-               if (!dev_set(pv->dev, start2,
-                            (size_t) (mda_size1 >
-                                      wipe_size ? : mda_size1), 0)) {
-                       log_error("Failed to wipe new metadata area");
-                       return 0;
-               }
-       } else
-               return 0;
-
        return 1;
 }
 
 /* Only for orphans */
-/* Set label_sector to -1 if rewriting existing label into same sector */
-/* If mdas is supplied it overwrites existing mdas e.g. used with pvcreate */
-static int _text_pv_write(const struct format_type *fmt, struct physical_volume *pv,
-                    struct dm_list *mdas, int64_t label_sector)
+static int _text_pv_write(const struct format_type *fmt, struct physical_volume *pv)
 {
+       struct format_instance *fid = pv->fid;
+       const char *pvid = (const char *) (*pv->old_id.uuid ? &pv->old_id : &pv->id);
        struct label *label;
        struct lvmcache_info *info;
        struct mda_context *mdac;
        struct metadata_area *mda;
-       char buf[MDA_HEADER_SIZE] __attribute__((aligned(8)));
-       struct mda_header *mdah = (struct mda_header *) buf;
-       uint64_t adjustment;
-       struct data_area_list *da;
-
-       /* FIXME Test mode don't update cache? */
+       struct _write_single_mda_baton baton;
+       unsigned mda_index;
 
-       if (!(info = lvmcache_add(fmt->labeller, (char *) &pv->id, pv->dev,
-                                 FMT_TEXT_ORPHAN_VG_NAME, NULL, 0)))
+       /* Add a new cache entry with PV info or update existing one. */
+       if (!(info = lvmcache_add(fmt->labeller, (const char *) &pv->id,
+                                 pv->dev, pv->vg_name, NULL, 0)))
                return_0;
-       label = info->label;
 
-       if (label_sector != -1)
-               label->sector = label_sector;
+       label = lvmcache_get_label(info);
+       label->sector = pv->label_sector;
 
-       info->device_size = pv->size << SECTOR_SHIFT;
-       info->fmt = fmt;
+       lvmcache_update_pv(info, pv, fmt);
 
-       /* If mdas supplied, use them regardless of existing ones, */
-       /* otherwise retain existing ones */
-       if (mdas) {
-               if (info->mdas.n)
-                       del_mdas(&info->mdas);
-               else
-                       dm_list_init(&info->mdas);
-               dm_list_iterate_items(mda, mdas) {
-                       mdac = mda->metadata_locn;
-                       log_debug("Creating metadata area on %s at sector %"
-                                 PRIu64 " size %" PRIu64 " sectors",
-                                 dev_name(mdac->area.dev),
-                                 mdac->area.start >> SECTOR_SHIFT,
-                                 mdac->area.size >> SECTOR_SHIFT);
-                       add_mda(fmt, NULL, &info->mdas, mdac->area.dev,
-                               mdac->area.start, mdac->area.size, mda_is_ignored(mda));
-               }
-               /* FIXME Temporary until mda creation supported by tools */
-       } else if (!info->mdas.n) {
-               dm_list_init(&info->mdas);
-       }
+       /* Flush all cached metadata areas, we will reenter new/modified ones. */
+       lvmcache_del_mdas(info);
 
        /*
-        * If no pe_start supplied but PV already exists,
-        * get existing value; use-cases include:
-        * - pvcreate on PV without prior pvremove
-        * - vgremove on VG with PV(s) that have pe_start=0 (hacked cfg)
+        * Add all new or modified metadata areas for this PV stored in
+        * its format instance. If this PV is not part of a VG yet,
+        * pv->fid will be used. Otherwise pv->vg->fid will be used.
+        * The fid_get_mda_indexed fn can handle that transparently,
+        * just pass the right format_instance in.
         */
-       if (info->das.n) {
-               if (!pv->pe_start)
-                       dm_list_iterate_items(da, &info->das)
-                               pv->pe_start = da->disk_locn.offset >> SECTOR_SHIFT;
-               del_das(&info->das);
-       } else
-               dm_list_init(&info->das);
+       for (mda_index = 0; mda_index < FMT_TEXT_MAX_MDAS_PER_PV; mda_index++) {
+               if (!(mda = fid_get_mda_indexed(fid, pvid, ID_LEN, mda_index)))
+                       continue;
+
+               mdac = (struct mda_context *) mda->metadata_locn;
+               log_debug("Creating metadata area on %s at sector %"
+                         PRIu64 " size %" PRIu64 " sectors",
+                         dev_name(mdac->area.dev),
+                         mdac->area.start >> SECTOR_SHIFT,
+                         mdac->area.size >> SECTOR_SHIFT);
+
+               // if fmt is not the same as info->fmt we are in trouble
+               lvmcache_add_mda(info, mdac->area.dev,
+                                mdac->area.start, mdac->area.size, mda_is_ignored(mda));
+       }
 
-#if 0
        /*
-        * FIXME: ideally a pre-existing pe_start seen in .pv_write
-        * would always be preserved BUT 'pvcreate on PV without prior pvremove'
-        * could easily cause the pe_start to overlap with the first mda!
+        * FIXME: Allow writing zero offset/size data area to disk.
+        *        This requires defining a special value since we can't
+        *        write offset/size that is 0/0 - this is already reserved
+        *        as a delimiter in data/metadata area area list in PV header
+        *        (needs exploring compatibility with older lvm2).
         */
-       if (pv->pe_start) {
-               log_very_verbose("%s: preserving pe_start=%lu",
-                                pv_dev_name(pv), pv->pe_start);
-               goto preserve_pe_start;
-       }
-#endif
 
        /*
-        * If pe_start is still unset, set it to first aligned
-        * sector after any metadata areas that begin before pe_start.
+        * We can't actually write pe_start = 0 (a data area offset)
+        * in PV header now. We need to replace this value here. This can
+        * happen with vgcfgrestore with redefined pe_start or
+        * pvcreate --restorefile. However, we can can have this value in
+        * metadata which will override the value in the PV header.
         */
-       if (!pv->pe_start) {
-               pv->pe_start = pv->pe_align;
-               if (pv->pe_align_offset)
-                       pv->pe_start += pv->pe_align_offset;
-       }
-       dm_list_iterate_items(mda, &info->mdas) {
-               mdac = (struct mda_context *) mda->metadata_locn;
-               if (pv->dev == mdac->area.dev &&
-                   ((mdac->area.start <= (pv->pe_start << SECTOR_SHIFT)) ||
-                   (mdac->area.start <= lvm_getpagesize() &&
-                    pv->pe_start < (lvm_getpagesize() >> SECTOR_SHIFT))) &&
-                   (mdac->area.start + mdac->area.size >
-                    (pv->pe_start << SECTOR_SHIFT))) {
-                       pv->pe_start = (mdac->area.start + mdac->area.size)
-                           >> SECTOR_SHIFT;
-                       /* Adjust pe_start to: (N * pe_align) + pe_align_offset */
-                       if (pv->pe_align) {
-                               adjustment =
-                               (pv->pe_start - pv->pe_align_offset) % pv->pe_align;
-                               if (adjustment)
-                                       pv->pe_start += (pv->pe_align - adjustment);
-
-                               log_very_verbose("%s: setting pe_start=%" PRIu64
-                                        " (orig_pe_start=%" PRIu64 ", "
-                                        "pe_align=%lu, pe_align_offset=%lu, "
-                                        "adjustment=%" PRIu64 ")",
-                                        pv_dev_name(pv), pv->pe_start,
-                                        (adjustment ?
-                                         pv->pe_start - (pv->pe_align - adjustment) :
-                                         pv->pe_start),
-                                        pv->pe_align, pv->pe_align_offset, adjustment);
-                       }
-               }
-       }
-       if (pv->pe_start >= pv->size) {
-               log_error("Data area is beyond end of device %s!",
-                         pv_dev_name(pv));
-               return 0;
-       }
 
-       /* FIXME: preserve_pe_start: */
-       if (!add_da
-           (NULL, &info->das, pv->pe_start << SECTOR_SHIFT, UINT64_C(0)))
+       if (!lvmcache_update_das(info, pv))
                return_0;
 
        if (!dev_open(pv->dev))
                return_0;
 
-       dm_list_iterate_items(mda, &info->mdas) {
-               mdac = mda->metadata_locn;
-               memset(&buf, 0, sizeof(buf));
-               mdah->size = mdac->area.size;
-               rlocn_set_ignored(mdah->raw_locns, mda_is_ignored(mda));
-               if (!_raw_write_mda_header(fmt, mdac->area.dev,
-                                          mdac->area.start, mdah)) {
-                       if (!dev_close(pv->dev))
-                               stack;
-                       return_0;
-               }
-       }
+       baton.pv = pv;
+       baton.fmt = fmt;
 
-       if (!label_write(pv->dev, label)) {
-               dev_close(pv->dev);
+       if (!lvmcache_foreach_mda(info, _write_single_mda, &baton))
                return_0;
+
+       if (!label_write(pv->dev, label)) {
+               stack;
+               if (!dev_close(pv->dev))
+                       stack;
+               return 0;
        }
 
+       /*
+        *  FIXME: We should probably use the format instance's metadata
+        *        areas for label_write and only if it's successful,
+        *        update the cache afterwards?
+        */
+
        if (!dev_close(pv->dev))
                return_0;
 
@@ -1578,56 +1397,6 @@ static int _add_raw(struct dm_list *raw_list, struct device_area *dev_area)
        return 1;
 }
 
-static int _get_pv_if_in_vg(struct lvmcache_info *info,
-                           struct physical_volume *pv)
-{
-       if (info->vginfo && info->vginfo->vgname &&
-           !is_orphan_vg(info->vginfo->vgname) &&
-           get_pv_from_vg_by_id(info->fmt, info->vginfo->vgname,
-                                info->vginfo->vgid, info->dev->pvid, pv))
-               return 1;
-
-       return 0;
-}
-
-static int _populate_pv_fields(struct lvmcache_info *info,
-                              struct physical_volume *pv,
-                              int scan_label_only)
-{
-       struct data_area_list *da;
-
-       /* Have we already cached vgname? */
-       if (!scan_label_only && _get_pv_if_in_vg(info, pv))
-               return 1;
-
-       /* Perform full scan (just the first time) and try again */
-       if (!scan_label_only && !memlock() && !full_scan_done()) {
-               lvmcache_label_scan(info->fmt->cmd, 2);
-
-               if (_get_pv_if_in_vg(info, pv))
-                       return 1;
-       }
-
-       /* Orphan */
-       pv->dev = info->dev;
-       pv->fmt = info->fmt;
-       pv->size = info->device_size >> SECTOR_SHIFT;
-       pv->vg_name = FMT_TEXT_ORPHAN_VG_NAME;
-       memcpy(&pv->id, &info->dev->pvid, sizeof(pv->id));
-
-       /* Currently only support exactly one data area */
-       if (dm_list_size(&info->das) != 1) {
-               log_error("Must be exactly one data area (found %d) on PV %s",
-                         dm_list_size(&info->das), dev_name(info->dev));
-               return 0;
-       }
-
-       dm_list_iterate_items(da, &info->das)
-               pv->pe_start = da->disk_locn.offset >> SECTOR_SHIFT;
-
-       return 1;
-}
-
 /*
  * Copy constructor for a metadata_locn.
  */
@@ -1663,40 +1432,107 @@ static uint64_t _metadata_locn_offset_raw(void *metadata_locn)
 }
 
 static int _text_pv_read(const struct format_type *fmt, const char *pv_name,
-                   struct physical_volume *pv, struct dm_list *mdas,
-                   int scan_label_only)
+                   struct physical_volume *pv, int scan_label_only)
 {
-       struct metadata_area *mda, *mda_new;
-       struct label *label;
-       struct device *dev;
        struct lvmcache_info *info;
+       struct device *dev;
 
        if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter)))
                return_0;
 
-       if (!(label_read(dev, &label, UINT64_C(0))))
+       if (lvmetad_active()) {
+               info = lvmcache_info_from_pvid(dev->pvid, 0);
+               if (!info && !lvmetad_pv_lookup_by_dev(fmt->cmd, dev, NULL))
+                       return 0;
+               info = lvmcache_info_from_pvid(dev->pvid, 0);
+       } else {
+               struct label *label;
+               if (!(label_read(dev, &label, UINT64_C(0))))
+                       return_0;
+               info = label->info;
+       }
+
+       if (!info)
                return_0;
-       info = (struct lvmcache_info *) label->info;
 
-       if (!_populate_pv_fields(info, pv, scan_label_only))
+       if (!lvmcache_populate_pv_fields(info, pv, scan_label_only))
                return 0;
 
-       if (!mdas)
-               return 1;
+       return 1;
+}
 
-       /* Add copy of mdas to supplied list */
-       dm_list_iterate_items(mda, &info->mdas) {
-               mda_new = mda_copy(fmt->cmd->mem, mda);
-               if (!mda_new)
-                       return 0;
-               dm_list_add(mdas, &mda_new->list);
+static int _text_pv_initialise(const struct format_type *fmt,
+                              const int64_t label_sector,
+                              uint64_t pe_start,
+                              uint32_t extent_count,
+                              uint32_t extent_size,
+                              unsigned long data_alignment,
+                              unsigned long data_alignment_offset,
+                              struct physical_volume *pv)
+{
+       /*
+        * Try to keep the value of PE start set to a firm value if requested.
+        * This is usefull when restoring existing PE start value (backups etc.).
+        */
+       if (pe_start != PV_PE_START_CALC)
+               pv->pe_start = pe_start;
+
+       if (!data_alignment)
+               data_alignment = find_config_tree_int(pv->fmt->cmd,
+                                             "devices/data_alignment",
+                                             0) * 2;
+
+       if (set_pe_align(pv, data_alignment) != data_alignment &&
+           data_alignment) {
+               log_error("%s: invalid data alignment of "
+                         "%lu sectors (requested %lu sectors)",
+                         pv_dev_name(pv), pv->pe_align, data_alignment);
+               return 0;
        }
 
+       if (set_pe_align_offset(pv, data_alignment_offset) != data_alignment_offset &&
+           data_alignment_offset) {
+               log_error("%s: invalid data alignment offset of "
+                         "%lu sectors (requested %lu sectors)",
+                         pv_dev_name(pv), pv->pe_align_offset, data_alignment_offset);
+               return 0;
+       }
+
+       if (pv->pe_align < pv->pe_align_offset) {
+               log_error("%s: pe_align (%lu sectors) must not be less "
+                         "than pe_align_offset (%lu sectors)",
+                         pv_dev_name(pv), pv->pe_align, pv->pe_align_offset);
+               return 0;
+       }
+
+       if (pe_start == PV_PE_START_CALC && pv->pe_start < pv->pe_align)
+               pv->pe_start = pv->pe_align;
+
+       if (extent_size)
+               pv->pe_size = extent_size;
+
+       if (extent_count)
+               pv->pe_count = extent_count;
+
+       if ((pv->pe_start + pv->pe_count * pv->pe_size - 1) > (pv->size << SECTOR_SHIFT)) {
+               log_error("Physical extents end beyond end of device %s.",
+                          pv_dev_name(pv));
+               return 0;
+       }
+
+       if (label_sector != -1)
+                pv->label_sector = label_sector;
+
        return 1;
 }
 
-static void _text_destroy_instance(struct format_instance *fid __attribute__((unused)))
+static void _text_destroy_instance(struct format_instance *fid)
 {
+       if (--fid->ref_count <= 1) {
+               if (fid->metadata_areas_index)
+                       dm_hash_destroy(fid->metadata_areas_index);
+               dm_pool_destroy(fid->mem);
+       }
 }
 
 static void _free_dirs(struct dm_list *dir_list)
@@ -1721,6 +1557,9 @@ static void _free_raws(struct dm_list *raw_list)
 
 static void _text_destroy(struct format_type *fmt)
 {
+       if (fmt->orphan_vg)
+               free_orphan_vg(fmt->orphan_vg);
+
        if (fmt->private) {
                _free_dirs(&((struct mda_lists *) fmt->private)->dirs);
                _free_raws(&((struct mda_lists *) fmt->private)->raws);
@@ -1745,6 +1584,11 @@ static struct metadata_area_ops _metadata_text_file_backup_ops = {
        .vg_commit = _vg_commit_file_backup
 };
 
+static int _mda_export_text_raw(struct metadata_area *mda,
+                               struct dm_config_tree *cft,
+                               struct dm_config_node *parent);
+static int _mda_import_text_raw(struct lvmcache_info *info, const struct dm_config_node *cn);
+
 static struct metadata_area_ops _metadata_text_raw_ops = {
        .vg_read = _vg_read_raw,
        .vg_read_precommit = _vg_read_precommit_raw,
@@ -1760,297 +1604,643 @@ static struct metadata_area_ops _metadata_text_raw_ops = {
        .mda_total_sectors = _mda_total_sectors_raw,
        .mda_in_vg = _mda_in_vg_raw,
        .pv_analyze_mda = _pv_analyze_mda_raw,
-       .mda_locns_match = _mda_locns_match_raw
+       .mda_locns_match = _mda_locns_match_raw,
+       .mda_get_device = _mda_get_device_raw,
+       .mda_export_text = _mda_export_text_raw,
+       .mda_import_text = _mda_import_text_raw
 };
 
-/* pvmetadatasize in sectors */
-/*
- * pe_start goal: FIXME -- reality of .pv_write complexity undermines this goal
- * - In cases where a pre-existing pe_start is provided (pvcreate --restorefile
- *   and vgconvert): pe_start must not be changed (so pv->pe_start = pe_start).
- * - In cases where pe_start is 0: leave pv->pe_start as 0 and defer the
- *   setting of pv->pe_start to .pv_write
- */
+static int _mda_export_text_raw(struct metadata_area *mda,
+                               struct dm_config_tree *cft,
+                               struct dm_config_node *parent)
+{
+       struct mda_context *mdc = (struct mda_context *) mda->metadata_locn;
+
+       return config_make_nodes(cft, parent, NULL,
+                                "ignore = %" PRId64, (int64_t) mda_is_ignored(mda),
+                                "start = %" PRId64, (int64_t) mdc->area.start,
+                                "size = %" PRId64, (int64_t) mdc->area.size,
+                                "free_sectors = %" PRId64, (int64_t) mdc->free_sectors,
+                                NULL) ? 1 : 0;
+}
+
+static int _mda_import_text_raw(struct lvmcache_info *info, const struct dm_config_node *cn)
+{
+       struct device *device;
+       uint64_t offset;
+       uint64_t size;
+       int ignore;
+
+       if (!cn->child)
+               return 0;
+
+       cn = cn->child;
+       device = lvmcache_device(info);
+       size = dm_config_find_int(cn, "size", 0);
+
+       if (!device || !size)
+               return 0;
+
+       offset = dm_config_find_int(cn, "start", 0);
+       ignore = dm_config_find_int(cn, "ignore", 0);
+
+       lvmcache_add_mda(info, device, offset, size, ignore);
+
+       return 1;
+}
+
 static int _text_pv_setup(const struct format_type *fmt,
-                         uint64_t pe_start, uint32_t extent_count,
-                         uint32_t extent_size, unsigned long data_alignment,
-                         unsigned long data_alignment_offset,
-                         int pvmetadatacopies, uint64_t pvmetadatasize,
-                         unsigned metadataignore, struct dm_list *mdas,
-                         struct physical_volume *pv, struct volume_group *vg)
+                         struct physical_volume *pv,
+                         struct volume_group *vg)
 {
-       struct metadata_area *mda, *mda_new, *mda2;
-       struct mda_context *mdac, *mdac2;
-       struct dm_list *pvmdas;
+       struct format_instance *fid = pv->fid;
+       const char *pvid = (const char *) (*pv->old_id.uuid ? &pv->old_id : &pv->id);
        struct lvmcache_info *info;
-       int found;
-       uint64_t pe_end = 0;
-       unsigned mda_count = 0;
-       uint64_t mda_size2 = 0;
+       unsigned mda_index;
+       struct metadata_area *pv_mda, *pv_mda_copy;
+       struct mda_context *pv_mdac;
        uint64_t pe_count;
+       uint64_t size_reduction = 0;
 
-       /* FIXME Cope with pvchange */
-       /* FIXME Merge code with _text_create_text_instance */
-
-       /* If new vg, add any further mdas on this PV to the fid's mda list */
-       if (vg) {
-               /* Iterate through all mdas on this PV */
-               if ((info = info_from_pvid(pv->dev->pvid, 0))) {
-                       pvmdas = &info->mdas;
-                       dm_list_iterate_items(mda, pvmdas) {
-                               mda_count++;
-                               mdac =
-                                   (struct mda_context *) mda->metadata_locn;
-
-                               /* FIXME Check it isn't already in use */
-
-                               /* Reduce usable device size */
-                               if (mda_count > 1)
-                                       mda_size2 = mdac->area.size >> SECTOR_SHIFT;
-
-                               /* Ensure it isn't already on list */
-                               found = 0;
-                               dm_list_iterate_items(mda2, mdas) {
-                                       if (mda2->ops !=
-                                           &_metadata_text_raw_ops) continue;
-                                       mdac2 =
-                                           (struct mda_context *)
-                                           mda2->metadata_locn;
-                                       if (!memcmp
-                                           (&mdac2->area, &mdac->area,
-                                            sizeof(mdac->area))) {
-                                               found = 1;
-                                               break;
-                                       }
-                               }
-                               if (found)
-                                       continue;
+       /* If PV has its own format instance, add mdas from pv->fid to vg->fid. */
+       if (pv->fid != vg->fid) {
+               for (mda_index = 0; mda_index < FMT_TEXT_MAX_MDAS_PER_PV; mda_index++) {
+                       if (!(pv_mda = fid_get_mda_indexed(fid, pvid, ID_LEN, mda_index)))
+                               continue;
 
-                               mda_new = mda_copy(fmt->cmd->mem, mda);
-                               if (!mda_new)
+                       /* Be sure it's not already in VG's format instance! */
+                       if (!fid_get_mda_indexed(vg->fid, pvid, ID_LEN, mda_index)) {
+                               if (!(pv_mda_copy = mda_copy(vg->fid->mem, pv_mda)))
                                        return_0;
-                               dm_list_add(mdas, &mda_new->list);
-                               /* FIXME multiple dev_areas inside area */
+                               fid_add_mda(vg->fid, pv_mda_copy, pvid, ID_LEN, mda_index);
                        }
                }
-
-               /* FIXME Cope with genuine pe_count 0 */
-
-               /* If missing, estimate pv->size from file-based metadata */
-               if (!pv->size && pv->pe_count)
-                       pv->size = pv->pe_count * (uint64_t) vg->extent_size +
-                                  pv->pe_start + mda_size2;
-
-               /* Recalculate number of extents that will fit */
-               if (!pv->pe_count) {
-                       pe_count = (pv->size - pv->pe_start - mda_size2) /
-                                  vg->extent_size;
-                       if (pe_count > UINT32_MAX) {
-                               log_error("PV %s too large for extent size %s.",
-                                         pv_dev_name(pv),
-                                         display_size(vg->cmd, (uint64_t) vg->extent_size));
-                               return 0;
-                       }
-                       pv->pe_count = (uint32_t) pe_count;
-               }
-
-               /* Unlike LVM1, we don't store this outside a VG */
-               /* FIXME Default from config file? vgextend cmdline flag? */
-               pv->status |= ALLOCATABLE_PV;
-       } else {
-               if (pe_start)
-                       pv->pe_start = pe_start;
-
-               if (!data_alignment)
-                       data_alignment = find_config_tree_int(pv->fmt->cmd,
-                                                     "devices/data_alignment",
-                                                     0) * 2;
-
-               if (set_pe_align(pv, data_alignment) != data_alignment &&
-                   data_alignment) {
-                       log_error("%s: invalid data alignment of "
-                                 "%lu sectors (requested %lu sectors)",
-                                 pv_dev_name(pv), pv->pe_align, data_alignment);
+       }
+       /*
+        * Otherwise, if the PV is already a part of the VG (pv->fid == vg->fid),
+        * reread PV mda information from the cache and add it to vg->fid.
+        */
+       else {
+               if (!pv->dev ||
+                   !(info = lvmcache_info_from_pvid(pv->dev->pvid, 0))) {
+                       log_error("PV %s missing from cache", pv_dev_name(pv));
                        return 0;
                }
 
-               if (set_pe_align_offset(pv, data_alignment_offset) != data_alignment_offset &&
-                   data_alignment_offset) {
-                       log_error("%s: invalid data alignment offset of "
-                                 "%lu sectors (requested %lu sectors)",
-                                 pv_dev_name(pv), pv->pe_align_offset, data_alignment_offset);
-                       return 0;
-               }
+               if (!lvmcache_check_format(info, fmt))
+                       return_0;
+
+               if (!lvmcache_fid_add_mdas_pv(info, fid))
+                       return_0;
+       }
+
+       /* If there's the 2nd mda, we need to reduce
+        * usable size for further pe_count calculation! */
+       if ((pv_mda = fid_get_mda_indexed(fid, pvid, ID_LEN, 1)) &&
+           (pv_mdac = pv_mda->metadata_locn))
+               size_reduction = pv_mdac->area.size >> SECTOR_SHIFT;
+
+       /* From now on, VG format instance will be used. */
+       pv_set_fid(pv, vg->fid);
 
-               if (pv->pe_align < pv->pe_align_offset) {
-                       log_error("%s: pe_align (%lu sectors) must not be less "
-                                 "than pe_align_offset (%lu sectors)",
-                                 pv_dev_name(pv), pv->pe_align, pv->pe_align_offset);
+       /* FIXME Cope with genuine pe_count 0 */
+
+       /* If missing, estimate pv->size from file-based metadata */
+       if (!pv->size && pv->pe_count)
+               pv->size = pv->pe_count * (uint64_t) vg->extent_size +
+                          pv->pe_start + size_reduction;
+
+       /* Recalculate number of extents that will fit */
+       if (!pv->pe_count && vg->extent_size) {
+               pe_count = (pv->size - pv->pe_start - size_reduction) /
+                          vg->extent_size;
+               if (pe_count > UINT32_MAX) {
+                       log_error("PV %s too large for extent size %s.",
+                                 pv_dev_name(pv),
+                                 display_size(vg->cmd, (uint64_t) vg->extent_size));
                        return 0;
                }
+               pv->pe_count = (uint32_t) pe_count;
+       }
 
-               /*
-                * This initialization has a side-effect of allowing
-                * orphaned PVs to be created with the proper alignment.
-                * Setting pv->pe_start here circumvents .pv_write's
-                * "pvcreate on PV without prior pvremove" retreival of
-                * the PV's previous pe_start.
-                * - Without this you get actual != expected pe_start
-                *   failures in the testsuite.
-                */
-               if (!pe_start && pv->pe_start < pv->pe_align)
-                       pv->pe_start = pv->pe_align;
+       /* Unlike LVM1, we don't store this outside a VG */
+       /* FIXME Default from config file? vgextend cmdline flag? */
+       pv->status |= ALLOCATABLE_PV;
 
-               if (extent_count)
-                       pe_end = pe_start + extent_count * extent_size - 1;
-               if (!_mda_setup(fmt, pe_start, pe_end, pvmetadatacopies,
-                               pvmetadatasize, metadataignore,  mdas, pv, vg))
-                       return_0;
+       return 1;
+}
+
+static void *_create_text_context(struct dm_pool *mem, struct text_context *tc)
+{
+       struct text_context *new_tc;
+       const char *path;
+       char *tmp;
+
+       if (!tc)
+               return NULL;
+
+       path = tc->path_live;
+
+       if ((tmp = strstr(path, ".tmp")) && (tmp == path + strlen(path) - 4)) {
+               log_error("%s: Volume group filename may not end in .tmp",
+                         path);
+               return NULL;
        }
 
-       return 1;
+       if (!(new_tc = dm_pool_alloc(mem, sizeof(*new_tc))))
+               return_NULL;
+
+       if (!(new_tc->path_live = dm_pool_strdup(mem, path)))
+               goto_bad;
+
+       /* If path_edit not defined, create one from path_live with .tmp suffix. */
+       if (!tc->path_edit) {
+               if (!(tmp = dm_pool_alloc(mem, strlen(path) + 5)))
+                       goto_bad;
+               sprintf(tmp, "%s.tmp", path);
+               new_tc->path_edit = tmp;
+       }
+       else if (!(new_tc->path_edit = dm_pool_strdup(mem, tc->path_edit)))
+               goto_bad;
+
+       if (!(new_tc->desc = tc->desc ? dm_pool_strdup(mem, tc->desc)
+                                     : dm_pool_strdup(mem, "")))
+               goto_bad;
+
+       return (void *) new_tc;
+
+      bad:
+       dm_pool_free(mem, new_tc);
+
+       log_error("Couldn't allocate text format context object.");
+       return NULL;
 }
 
-/* NULL vgname means use only the supplied context e.g. an archive file */
-static struct format_instance *_text_create_text_instance(const struct format_type
-                                                    *fmt, const char *vgname,
-                                                    const char *vgid,
-                                                    void *context)
+static int _create_vg_text_instance(struct format_instance *fid,
+                                    const struct format_instance_ctx *fic)
 {
-       struct format_instance *fid;
+       static char path[PATH_MAX];
+       uint32_t type = fic->type;
        struct text_fid_context *fidtc;
        struct metadata_area *mda;
        struct mda_context *mdac;
        struct dir_list *dl;
        struct raw_list *rl;
        struct dm_list *dir_list, *raw_list;
-       char path[PATH_MAX];
+       struct text_context tc;
        struct lvmcache_vginfo *vginfo;
-       struct lvmcache_info *info;
-
-       if (!(fid = dm_pool_alloc(fmt->cmd->mem, sizeof(*fid)))) {
-               log_error("Couldn't allocate format instance object.");
-               return NULL;
-       }
+       const char *vg_name, *vg_id;
 
        if (!(fidtc = (struct text_fid_context *)
-                       dm_pool_zalloc(fmt->cmd->mem,sizeof(*fidtc)))) {
+                       dm_pool_zalloc(fid->mem, sizeof(*fidtc)))) {
                log_error("Couldn't allocate text_fid_context.");
-               return NULL;
+               return 0;
        }
 
        fidtc->raw_metadata_buf = NULL;
        fid->private = (void *) fidtc;
 
-       fid->fmt = fmt;
-       dm_list_init(&fid->metadata_areas_in_use);
-       dm_list_init(&fid->metadata_areas_ignored);
-
-       if (!vgname) {
-               if (!(mda = dm_pool_zalloc(fmt->cmd->mem, sizeof(*mda))))
-                       return_NULL;
+       if (type & FMT_INSTANCE_PRIVATE_MDAS) {
+               if (!(mda = dm_pool_zalloc(fid->mem, sizeof(*mda))))
+                       return_0;
                mda->ops = &_metadata_text_file_backup_ops;
-               mda->metadata_locn = context;
+               mda->metadata_locn = _create_text_context(fid->mem, fic->context.private);
                mda->status = 0;
-               fid_add_mda(fid, mda);
+               fid->metadata_areas_index = NULL;
+               fid_add_mda(fid, mda, NULL, 0, 0);
        } else {
-               dir_list = &((struct mda_lists *) fmt->private)->dirs;
-
-               dm_list_iterate_items(dl, dir_list) {
-                       if (dm_snprintf(path, PATH_MAX, "%s/%s",
-                                        dl->dir, vgname) < 0) {
-                               log_error("Name too long %s/%s", dl->dir,
-                                         vgname);
-                               return NULL;
-                       }
+               vg_name = fic->context.vg_ref.vg_name;
+               vg_id = fic->context.vg_ref.vg_id;
 
-                       context = create_text_context(fmt->cmd, path, NULL);
-                       if (!(mda = dm_pool_zalloc(fmt->cmd->mem, sizeof(*mda))))
-                               return_NULL;
-                       mda->ops = &_metadata_text_file_ops;
-                       mda->metadata_locn = context;
-                       mda->status = 0;
-                       fid_add_mda(fid, mda);
+               if (!(fid->metadata_areas_index = dm_hash_create(128))) {
+                       log_error("Couldn't create metadata index for format "
+                                 "instance of VG %s.", vg_name);
+                       return 0;
                }
 
-               raw_list = &((struct mda_lists *) fmt->private)->raws;
+               if (type & FMT_INSTANCE_AUX_MDAS) {
+                       dir_list = &((struct mda_lists *) fid->fmt->private)->dirs;
+                       dm_list_iterate_items(dl, dir_list) {
+                               if (dm_snprintf(path, PATH_MAX, "%s/%s", dl->dir, vg_name) < 0) {
+                                       log_error("Name too long %s/%s", dl->dir, vg_name);
+                                       return 0;
+                               }
+
+                               if (!(mda = dm_pool_zalloc(fid->mem, sizeof(*mda))))
+                                       return_0;
+                               mda->ops = &_metadata_text_file_ops;
+                               tc.path_live = path;
+                               tc.path_edit = tc.desc = NULL;
+                               mda->metadata_locn = _create_text_context(fid->mem, &tc);
+                               mda->status = 0;
+                               fid_add_mda(fid, mda, NULL, 0, 0);
+                       }
+
+                       raw_list = &((struct mda_lists *) fid->fmt->private)->raws;
+                       dm_list_iterate_items(rl, raw_list) {
+                               /* FIXME Cache this; rescan below if some missing */
+                               if (!_raw_holds_vgname(fid, &rl->dev_area, vg_name))
+                                       continue;
 
-               dm_list_iterate_items(rl, raw_list) {
-                       /* FIXME Cache this; rescan below if some missing */
-                       if (!_raw_holds_vgname(fid, &rl->dev_area, vgname))
-                               continue;
+                               if (!(mda = dm_pool_zalloc(fid->mem, sizeof(*mda))))
+                                       return_0;
 
-                       if (!(mda = dm_pool_zalloc(fmt->cmd->mem, sizeof(*mda))))
-                               return_NULL;
-
-                       if (!(mdac = dm_pool_zalloc(fmt->cmd->mem, sizeof(*mdac))))
-                               return_NULL;
-                       mda->metadata_locn = mdac;
-                       /* FIXME Allow multiple dev_areas inside area */
-                       memcpy(&mdac->area, &rl->dev_area, sizeof(mdac->area));
-                       mda->ops = &_metadata_text_raw_ops;
-                       mda->status = 0;
-                       /* FIXME MISTAKE? mda->metadata_locn = context; */
-                       fid_add_mda(fid, mda);
+                               if (!(mdac = dm_pool_zalloc(fid->mem, sizeof(*mdac))))
+                                       return_0;
+                               mda->metadata_locn = mdac;
+                               /* FIXME Allow multiple dev_areas inside area */
+                               memcpy(&mdac->area, &rl->dev_area, sizeof(mdac->area));
+                               mda->ops = &_metadata_text_raw_ops;
+                               mda->status = 0;
+                               /* FIXME MISTAKE? mda->metadata_locn = context; */
+                               fid_add_mda(fid, mda, NULL, 0, 0);
+                       }
                }
 
-               /* Scan PVs in VG for any further MDAs */
-               lvmcache_label_scan(fmt->cmd, 0);
-               if (!(vginfo = vginfo_from_vgname(vgname, vgid)))
-                       goto_out;
-               dm_list_iterate_items(info, &vginfo->infos) {
-                       if (!fid_add_mdas(fid, &info->mdas))
-                               return_NULL;
+               if (type & FMT_INSTANCE_MDAS) {
+                       /* Scan PVs in VG for any further MDAs */
+                       lvmcache_label_scan(fid->fmt->cmd, 0);
+                       if (!(vginfo = lvmcache_vginfo_from_vgname(vg_name, vg_id)))
+                               goto_out;
+                       if (!lvmcache_fid_add_mdas_vg(vginfo, fid))
+                               goto_out;
                }
+
                /* FIXME Check raw metadata area count - rescan if required */
        }
 
-      out:
-       return fid;
+out:
+       return 1;
 }
 
-void *create_text_context(struct cmd_context *cmd, const char *path,
-                         const char *desc)
+static int _add_metadata_area_to_pv(struct physical_volume *pv,
+                                   unsigned mda_index,
+                                   uint64_t mda_start,
+                                   uint64_t mda_size,
+                                   unsigned mda_ignored)
 {
-       struct text_context *tc;
-       char *tmp;
+       struct metadata_area *mda;
+       struct mda_context *mdac;
+       struct mda_lists *mda_lists = (struct mda_lists *) pv->fmt->private;
 
-       if ((tmp = strstr(path, ".tmp")) && (tmp == path + strlen(path) - 4)) {
-               log_error("%s: Volume group filename may not end in .tmp",
-                         path);
-               return NULL;
+       if (mda_index >= FMT_TEXT_MAX_MDAS_PER_PV) {
+               log_error(INTERNAL_ERROR "can't add metadata area with "
+                                        "index %u to PV %s. Metadata "
+                                        "layout not supported by %s format.",
+                                         mda_index, dev_name(pv->dev),
+                                         pv->fmt->name);
        }
 
-       if (!(tc = dm_pool_alloc(cmd->mem, sizeof(*tc))))
-               return_NULL;
+       if (!(mda = dm_pool_zalloc(pv->fid->mem, sizeof(struct metadata_area)))) {
+               log_error("struct metadata_area allocation failed");
+               return 0;
+       }
 
-       if (!(tc->path_live = dm_pool_strdup(cmd->mem, path)))
-               goto_bad;
+       if (!(mdac = dm_pool_zalloc(pv->fid->mem, sizeof(struct mda_context)))) {
+               log_error("struct mda_context allocation failed");
+               dm_free(mda);
+               return 0;
+       }
 
-       if (!(tc->path_edit = dm_pool_alloc(cmd->mem, strlen(path) + 5)))
-               goto_bad;
+       mda->ops = mda_lists->raw_ops;
+       mda->metadata_locn = mdac;
+       mda->status = 0;
 
-       sprintf(tc->path_edit, "%s.tmp", path);
+       mdac->area.dev = pv->dev;
+       mdac->area.start = mda_start;
+       mdac->area.size = mda_size;
+       mdac->free_sectors = UINT64_C(0);
+       memset(&mdac->rlocn, 0, sizeof(mdac->rlocn));
+       mda_set_ignored(mda, mda_ignored);
 
-       if (!desc)
-               desc = "";
+       fid_add_mda(pv->fid, mda, (char *) &pv->id, ID_LEN, mda_index);
 
-       if (!(tc->desc = dm_pool_strdup(cmd->mem, desc)))
-               goto_bad;
+       return 1;
+}
 
-       return (void *) tc;
+static int _text_pv_remove_metadata_area(const struct format_type *fmt,
+                                        struct physical_volume *pv,
+                                        unsigned mda_index);
 
-      bad:
-       dm_pool_free(cmd->mem, tc);
+static int _text_pv_add_metadata_area(const struct format_type *fmt,
+                                     struct physical_volume *pv,
+                                     int pe_start_locked,
+                                     unsigned mda_index,
+                                     uint64_t mda_size,
+                                     unsigned mda_ignored)
+{
+       struct format_instance *fid = pv->fid;
+       const char *pvid = (const char *) (*pv->old_id.uuid ? &pv->old_id : &pv->id);
+       uint64_t pe_start, pe_end;
+       uint64_t alignment, alignment_offset;
+       uint64_t disk_size;
+       uint64_t mda_start;
+       uint64_t adjustment, limit, tmp_mda_size;
+       uint64_t wipe_size = 8 << SECTOR_SHIFT;
+       size_t page_size = lvm_getpagesize();
+       struct metadata_area *mda;
+       struct mda_context *mdac;
+       const char *limit_name;
+       int limit_applied = 0;
+
+       if (mda_index >= FMT_TEXT_MAX_MDAS_PER_PV) {
+               log_error(INTERNAL_ERROR "invalid index of value %u used "
+                             "while trying to add metadata area on PV %s. "
+                             "Metadata layout not supported by %s format.",
+                              mda_index, pv_dev_name(pv), fmt->name);
+               return 0;
+       }
 
-       log_error("Couldn't allocate text format context object.");
+       pe_start = pv->pe_start << SECTOR_SHIFT;
+       alignment = pv->pe_align << SECTOR_SHIFT;
+       alignment_offset = pv->pe_align_offset << SECTOR_SHIFT;
+       disk_size = pv->size << SECTOR_SHIFT;
+       mda_size = mda_size << SECTOR_SHIFT;
+
+       if (fid_get_mda_indexed(fid, pvid, ID_LEN, mda_index)) {
+               if (!_text_pv_remove_metadata_area(fmt, pv, mda_index)) {
+                       log_error(INTERNAL_ERROR "metadata area with index %u already "
+                                 "exists on PV %s and removal failed.",
+                                 mda_index, pv_dev_name(pv));
+                       return 0;
+               }
+       }
+
+       /* First metadata area at the start of the device. */
+       if (mda_index == 0) {
+               /*
+                * Try to fit MDA0 end within given pe_start limit if its value
+                * is locked. If it's not locked, count with any existing MDA1.
+                * If there's no MDA1, just use disk size as the limit.
+                */
+               if (pe_start_locked) {
+                       limit = pe_start;
+                       limit_name = "pe_start";
+               }
+               else if ((mda = fid_get_mda_indexed(fid, pvid, ID_LEN, 1)) &&
+                        (mdac = mda->metadata_locn)) {
+                       limit = mdac->area.start;
+                       limit_name = "MDA1 start";
+               }
+               else {
+                       limit = disk_size;
+                       limit_name = "disk size";
+               }
+
+               if (limit > disk_size)
+                       goto bad;
+
+               mda_start = LABEL_SCAN_SIZE;
+
+               /* Align MDA0 start with page size if possible. */
+               if (limit - mda_start >= MDA_SIZE_MIN) {
+                       if ((adjustment = mda_start % page_size))
+                               mda_start += (page_size - adjustment);
+               }
+
+               /* Align MDA0 end position with given alignment if possible. */
+               if (alignment &&
+                   (adjustment = (mda_start + mda_size) % alignment)) {
+                       tmp_mda_size = mda_size + alignment - adjustment;
+                       if (mda_start + tmp_mda_size <= limit)
+                               mda_size = tmp_mda_size;
+               }
+
+               /* Align MDA0 end position with given alignment offset if possible. */
+               if (alignment_offset &&
+                   (((mda_start + mda_size) % alignment) == 0)) {
+                       tmp_mda_size = mda_size + alignment_offset;
+                       if (mda_start + tmp_mda_size <= limit)
+                               mda_size = tmp_mda_size;
+               }
+
+               if (mda_start + mda_size > limit) {
+                       /*
+                        * Try to decrease the MDA0 size with twice the
+                        * alignment and then align with given alignment.
+                        * If pe_start is locked, skip this type of
+                        * alignment since it would be useless.
+                        * Check first whether we can apply that!
+                        */
+                       if (!pe_start_locked &&
+                           ((limit - mda_start) > alignment * 2)) {
+                               mda_size = limit - mda_start - alignment * 2;
+
+                               if ((adjustment = (mda_start + mda_size) % alignment))
+                                       mda_size += (alignment - adjustment);
+
+                               /* Still too much? Then there's nothing else to do. */
+                               if (mda_start + mda_size > limit)
+                                       goto bad;
+                       }
+                       /* Otherwise, give up and take any usable space. */
+                       /* FIXME: We should probably check for some minimum MDA size here. */
+                       else
+                               mda_size = limit - mda_start;
+
+                       limit_applied = 1;
+               }
+
+               /*
+                * If PV's pe_start is not locked, update pe_start value with the
+                * start of the area that follows the MDA0 we've just calculated.
+                */
+               if (!pe_start_locked) {
+                       pe_start = mda_start + mda_size;
+                       pv->pe_start = pe_start >> SECTOR_SHIFT;
+               }
+       }
+       /* Second metadata area at the end of the device. */
+       else {
+               /*
+                * Try to fit MDA1 start within given pe_end or pe_start limit
+                * if defined or locked. If pe_start is not defined yet, count
+                * with any existing MDA0. If MDA0 does not exist, just use
+                * LABEL_SCAN_SIZE.
+                */
+               pe_end = pv->pe_count ? (pv->pe_start +
+                                        pv->pe_count * pv->pe_size - 1) << SECTOR_SHIFT
+                                     : 0;
+
+               if (pe_start || pe_start_locked) {
+                       limit = pe_end ? pe_end : pe_start;
+                       limit_name = pe_end ? "pe_end" : "pe_start";
+               }
+               else if ((mda = fid_get_mda_indexed(fid, pvid, ID_LEN, 0)) &&
+                        (mdac = mda->metadata_locn)) {
+                       limit = mdac->area.start + mdac->area.size;
+                       limit_name = "MDA0 end";
+               }
+               else {
+                       limit = LABEL_SCAN_SIZE;
+                       limit_name = "label scan size";
+               }
+
+               if (limit > disk_size)
+                       goto bad;
+
+               if (mda_size > disk_size) {
+                       mda_size = disk_size - limit;
+                       limit_applied = 1;
+               }
+
+               mda_start = disk_size - mda_size;
+
+               /* If MDA1 size is too big, just take any usable space. */
+               if (disk_size - mda_size < limit) {
+                       mda_size = disk_size - limit;
+                       mda_start = disk_size - mda_size;
+                       limit_applied = 1;
+               }
+               /* Otherwise, try to align MDA1 start if possible. */
+               else if (alignment &&
+                   (adjustment = mda_start % alignment)) {
+                       tmp_mda_size = mda_size + adjustment;
+                       if (tmp_mda_size < disk_size &&
+                           disk_size - tmp_mda_size >= limit) {
+                               mda_size = tmp_mda_size;
+                               mda_start = disk_size - mda_size;
+                       }
+               }
+
+               /*
+                * If PV's pe_end not set yet, set it to the end of the
+                * area that precedes the MDA1 we've just calculated.
+                * FIXME: do we need to set this? Isn't it always set before?
+                */
+               /*if (!pe_end) {
+                       pe_end = mda_start;
+                       pv->pe_end = pe_end >> SECTOR_SHIFT;
+               }*/
+       }
+
+       if (limit_applied)
+               log_very_verbose("Using limited metadata area size on %s "
+                                "with value %" PRIu64 " (limited by %s of "
+                                "%" PRIu64 ").", pv_dev_name(pv),
+                                 mda_size, limit_name, limit);
+
+       if (mda_size) {
+               /* Wipe metadata area with zeroes. */
+               if (!dev_set((struct device *) pv->dev, mda_start,
+                       (size_t) ((mda_size > wipe_size) ?
+                                 wipe_size : mda_size), 0)) {
+                               log_error("Failed to wipe new metadata area "
+                                         "at the %s of the %s",
+                                          mda_index ? "end" : "start",
+                                          pv_dev_name(pv));
+                               return 0;
+               }
+
+               /* Finally, add new metadata area to PV's format instance. */
+               if (!_add_metadata_area_to_pv(pv, mda_index, mda_start,
+                                             mda_size, mda_ignored))
+                       return_0;
+       }
+
+       return 1;
+
+bad:
+       log_error("Not enough space available for metadata area "
+                 "with index %u on PV %s.", mda_index, pv_dev_name(pv));
+       return 0;
+}
+
+static int _remove_metadata_area_from_pv(struct physical_volume *pv,
+                                        unsigned mda_index)
+{
+       if (mda_index >= FMT_TEXT_MAX_MDAS_PER_PV) {
+               log_error(INTERNAL_ERROR "can't remove metadata area with "
+                                        "index %u from PV %s. Metadata "
+                                        "layou not supported by %s format.",
+                                         mda_index, dev_name(pv->dev),
+                                         pv->fmt->name);
+               return 0;
+       }
+
+       return fid_remove_mda(pv->fid, NULL, (const char *) &pv->id,
+                             ID_LEN, mda_index);
+}
+
+static int _text_pv_remove_metadata_area(const struct format_type *fmt,
+                                        struct physical_volume *pv,
+                                        unsigned mda_index)
+{
+       return _remove_metadata_area_from_pv(pv, mda_index);
+}
+
+static int _text_pv_resize(const struct format_type *fmt,
+                          struct physical_volume *pv,
+                          struct volume_group *vg,
+                          uint64_t size)
+{
+       struct format_instance *fid = pv->fid;
+       const char *pvid = (const char *) (*pv->old_id.uuid ? &pv->old_id : &pv->id);
+       struct metadata_area *mda;
+       struct mda_context *mdac;
+       uint64_t size_reduction;
+       uint64_t mda_size;
+       unsigned mda_ignored;
+
+       /*
+        * First, set the new size and update the cache and reset pe_count.
+        * (pe_count must be reset otherwise it would be considered as
+        * a limiting factor while moving the mda!)
+        */
+       pv->size = size;
+       pv->pe_count = 0;
+
+       /* If there's an mda at the end, move it to a new position. */
+       if ((mda = fid_get_mda_indexed(fid, pvid, ID_LEN, 1)) &&
+           (mdac = mda->metadata_locn)) {
+               /* FIXME: Maybe MDA0 size would be better? */
+               mda_size = mdac->area.size >> SECTOR_SHIFT;
+               mda_ignored = mda_is_ignored(mda);
+
+               if (!_text_pv_remove_metadata_area(fmt, pv, 1) ||
+                   !_text_pv_add_metadata_area(fmt, pv, 1, 1, mda_size,
+                                               mda_ignored)) {
+                       log_error("Failed to move metadata area with index 1 "
+                                 "while resizing PV %s.", pv_dev_name(pv));
+                       return 0;
+               }
+       }
+
+       /* If there's a VG, reduce size by counting in pe_start and metadata areas. */
+       if (vg) {
+               size_reduction = pv_pe_start(pv);
+               if ((mda = fid_get_mda_indexed(fid, pvid, ID_LEN, 1)) &&
+                   (mdac = mda->metadata_locn))
+                       size_reduction += mdac->area.size >> SECTOR_SHIFT;
+               pv->size -= size_reduction;
+       }
+
+       return 1;
+}
+
+static struct format_instance *_text_create_text_instance(const struct format_type *fmt,
+                                                         const struct format_instance_ctx *fic)
+{
+       struct format_instance *fid;
+
+       if (!(fid = alloc_fid(fmt, fic)))
+               return_NULL;
+
+       if (_create_vg_text_instance(fid, fic))
+               return fid;
+
+       dm_pool_destroy(fid->mem);
        return NULL;
 }
 
 static struct format_handler _text_handler = {
        .scan = _text_scan,
        .pv_read = _text_pv_read,
+       .pv_initialise = _text_pv_initialise,
        .pv_setup = _text_pv_setup,
+       .pv_add_metadata_area = _text_pv_add_metadata_area,
+       .pv_remove_metadata_area = _text_pv_remove_metadata_area,
+       .pv_resize = _text_pv_resize,
        .pv_write = _text_pv_write,
        .vg_setup = _text_vg_setup,
        .lv_setup = _text_lv_setup,
@@ -2078,7 +2268,7 @@ static int _add_dir(const char *dir, struct dm_list *dir_list)
 }
 
 static int _get_config_disk_area(struct cmd_context *cmd,
-                                const struct config_node *cn, struct dm_list *raw_list)
+                                const struct dm_config_node *cn, struct dm_list *raw_list)
 {
        struct device_area dev_area;
        const char *id_str;
@@ -2089,21 +2279,21 @@ static int _get_config_disk_area(struct cmd_context *cmd,
                return 0;
        }
 
-       if (!get_config_uint64(cn, "start_sector", &dev_area.start)) {
+       if (!dm_config_get_uint64(cn, "start_sector", &dev_area.start)) {
                log_error("Missing start_sector in metadata disk_area section "
                          "of config file");
                return 0;
        }
        dev_area.start <<= SECTOR_SHIFT;
 
-       if (!get_config_uint64(cn, "size", &dev_area.size)) {
+       if (!dm_config_get_uint64(cn, "size", &dev_area.size)) {
                log_error("Missing size in metadata disk_area section "
                          "of config file");
                return 0;
        }
        dev_area.size <<= SECTOR_SHIFT;
 
-       if (!get_config_str(cn, "id", &id_str)) {
+       if (!dm_config_get_str(cn, "id", &id_str)) {
                log_error("Missing uuid in metadata disk_area section "
                          "of config file");
                return 0;
@@ -2115,7 +2305,7 @@ static int _get_config_disk_area(struct cmd_context *cmd,
                return 0;
        }
 
-       if (!(dev_area.dev = device_from_pvid(cmd, &id, NULL))) {
+       if (!(dev_area.dev = lvmcache_device_from_pvid(cmd, &id, NULL, NULL))) {
                char buffer[64] __attribute__((aligned(8)));
 
                if (!id_write_format(&id, buffer, sizeof(buffer)))
@@ -2132,13 +2322,17 @@ static int _get_config_disk_area(struct cmd_context *cmd,
 
 struct format_type *create_text_format(struct cmd_context *cmd)
 {
+       struct format_instance_ctx fic;
+       struct format_instance *fid;
        struct format_type *fmt;
-       const struct config_node *cn;
-       const struct config_value *cv;
+       const struct dm_config_node *cn;
+       const struct dm_config_value *cv;
        struct mda_lists *mda_lists;
 
-       if (!(fmt = dm_malloc(sizeof(*fmt))))
-               return_NULL;
+       if (!(fmt = dm_malloc(sizeof(*fmt)))) {
+               log_error("Failed to allocate text format type structure.");
+               return NULL;
+       }
 
        fmt->cmd = cmd;
        fmt->ops = &_text_handler;
@@ -2161,30 +2355,32 @@ struct format_type *create_text_format(struct cmd_context *cmd)
        mda_lists->raw_ops = &_metadata_text_raw_ops;
        fmt->private = (void *) mda_lists;
 
+       dm_list_init(&fmt->mda_ops);
+       dm_list_add(&fmt->mda_ops, &_metadata_text_raw_ops.list);
+
        if (!(fmt->labeller = text_labeller_create(fmt))) {
                log_error("Couldn't create text label handler.");
-               dm_free(fmt);
-               return NULL;
+               goto bad;
        }
 
        if (!(label_register_handler(FMT_TEXT_NAME, fmt->labeller))) {
                log_error("Couldn't register text label handler.");
-               dm_free(fmt);
-               return NULL;
+               fmt->labeller->ops->destroy(fmt->labeller);
+               goto bad;
        }
 
        if ((cn = find_config_tree_node(cmd, "metadata/dirs"))) {
                for (cv = cn->v; cv; cv = cv->next) {
-                       if (cv->type != CFG_STRING) {
+                       if (cv->type != DM_CFG_STRING) {
                                log_error("Invalid string in config file: "
                                          "metadata/dirs");
-                               goto err;
+                               goto bad;
                        }
 
                        if (!_add_dir(cv->v.str, &mda_lists->dirs)) {
                                log_error("Failed to add %s to text format "
                                          "metadata directory list ", cv->v.str);
-                               goto err;
+                               goto bad;
                        }
                        cmd->independent_metadata_areas = 1;
                }
@@ -2193,18 +2389,27 @@ struct format_type *create_text_format(struct cmd_context *cmd)
        if ((cn = find_config_tree_node(cmd, "metadata/disk_areas"))) {
                for (cn = cn->child; cn; cn = cn->sib) {
                        if (!_get_config_disk_area(cmd, cn, &mda_lists->raws))
-                               goto err;
+                               goto_bad;
                        cmd->independent_metadata_areas = 1;
                }
        }
 
+       if (!(fmt->orphan_vg = alloc_vg("text_orphan", cmd, fmt->orphan_vg_name)))
+               goto_bad;
+
+       fic.type = FMT_INSTANCE_AUX_MDAS;
+       fic.context.vg_ref.vg_name = fmt->orphan_vg_name;
+       fic.context.vg_ref.vg_id = NULL;
+       if (!(fid = _text_create_text_instance(fmt, &fic)))
+               goto_bad;
+
+       vg_set_fid(fmt->orphan_vg, fid);
+
        log_very_verbose("Initialised format: %s", fmt->name);
 
        return fmt;
+bad:
+       _text_destroy(fmt);
 
-      err:
-       _free_dirs(&mda_lists->dirs);
-
-       dm_free(fmt);
        return NULL;
 }
index 79365eaf803d901d988d601841e906712c28f1f9..d8ec25555b69aa274bbc60da6b6b52a6a8d8b4aa 100644 (file)
@@ -22,6 +22,7 @@
 #define FMT_TEXT_NAME "lvm2"
 #define FMT_TEXT_ALIAS "text"
 #define FMT_TEXT_ORPHAN_VG_NAME ORPHAN_VG_NAME(FMT_TEXT_NAME)
+#define FMT_TEXT_MAX_MDAS_PER_PV 2
 
 /*
  * Archives a vg config.  'retain_days' is the minimum number of
@@ -43,9 +44,12 @@ int backup_list(struct cmd_context *cmd, const char *dir, const char *vgname);
 /*
  * The text format can read and write a volume_group to a file.
  */
+struct text_context {
+       const char *path_live;  /* Path to file holding live metadata */
+       const char *path_edit;  /* Path to file holding edited metadata */
+       const char *desc;       /* Description placed inside file */
+};
 struct format_type *create_text_format(struct cmd_context *cmd);
-void *create_text_context(struct cmd_context *cmd, const char *path,
-                         const char *desc);
 
 struct labeller *text_labeller_create(const struct format_type *fmt);
 
@@ -54,9 +58,20 @@ int pvhdr_read(struct device *dev, char *buf);
 int add_da(struct dm_pool *mem, struct dm_list *das,
           uint64_t start, uint64_t size);
 void del_das(struct dm_list *das);
-
 int add_mda(const struct format_type *fmt, struct dm_pool *mem, struct dm_list *mdas,
            struct device *dev, uint64_t start, uint64_t size, unsigned ignored);
 void del_mdas(struct dm_list *mdas);
 
+/* On disk */
+struct disk_locn {
+       uint64_t offset;        /* Offset in bytes to start sector */
+       uint64_t size;          /* Bytes */
+} __attribute__ ((packed));
+
+/* Data areas (holding PEs) */
+struct data_area_list {
+       struct dm_list list;
+       struct disk_locn disk_locn;
+};
+
 #endif
index 3b56f086d45d358e13fc2e8ea2266f37020399e4..6a4afed7885d4a55571370f7e8bf09c6776bdcf5 100644 (file)
@@ -44,14 +44,14 @@ enum {
 };
 
 struct text_vg_version_ops {
-       int (*check_version) (const struct config_tree * cf);
+       int (*check_version) (const struct dm_config_tree * cf);
        struct volume_group *(*read_vg) (struct format_instance * fid,
-                                        const struct config_tree *cf,
+                                        const struct dm_config_tree *cf,
                                         unsigned use_cached_pvs);
-       void (*read_desc) (struct dm_pool * mem, const struct config_tree *cf,
+       void (*read_desc) (struct dm_pool * mem, const struct dm_config_tree *cf,
                           time_t *when, char **desc);
        const char *(*read_vgname) (const struct format_type *fmt,
-                                   const struct config_tree *cft,
+                                   const struct dm_config_tree *cft,
                                    struct id *vgid, uint64_t *vgstatus,
                                    char **creation_host);
 };
@@ -59,18 +59,19 @@ struct text_vg_version_ops {
 struct text_vg_version_ops *text_vg_vsn1_init(void);
 
 int print_flags(uint64_t status, int type, char *buffer, size_t size);
-int read_flags(uint64_t *status, int type, const struct config_value *cv);
+int read_flags(uint64_t *status, int type, const struct dm_config_value *cv);
 
 char *alloc_printed_tags(struct dm_list *tags);
-int read_tags(struct dm_pool *mem, struct dm_list *tags, const struct config_value *cv);
+int read_tags(struct dm_pool *mem, struct dm_list *tags, const struct dm_config_value *cv);
 
 int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
-int text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf);
+size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf);
 struct volume_group *text_vg_import_file(struct format_instance *fid,
                                         const char *file,
                                         time_t *when, char **desc);
 struct volume_group *text_vg_import_fd(struct format_instance *fid,
                                       const char *file,
+                                      int single_device,
                                       struct device *dev,
                                       off_t offset, uint32_t size,
                                       off_t offset2, uint32_t size2,
index 60f465fc8dd54b2bc0dfae8e5f3762678dc21805..8a05ca9f7f0bb5a62a7337b6fdf408e8e7519749 100644 (file)
@@ -16,9 +16,6 @@
 #include "lib.h"
 #include "metadata.h"
 #include "import-export.h"
-#include "display.h"
-#include "toolcontext.h"
-#include "lvmcache.h"
 
 /* FIXME Use tidier inclusion method */
 static struct text_vg_version_ops *(_text_vsn_list[2]);
@@ -43,18 +40,18 @@ const char *text_vgname_import(const struct format_type *fmt,
                               struct id *vgid, uint64_t *vgstatus,
                               char **creation_host)
 {
-       struct config_tree *cft;
+       struct dm_config_tree *cft;
        struct text_vg_version_ops **vsn;
        const char *vgname = NULL;
 
        _init_text_import();
 
-       if (!(cft = create_config_tree(NULL, 0)))
+       if (!(cft = config_file_open(NULL, 0)))
                return_NULL;
 
-       if ((!dev && !read_config_file(cft)) ||
-           (dev && !read_config_fd(cft, dev, offset, size,
-                                   offset2, size2, checksum_fn, checksum)))
+       if ((!dev && !config_file_read(cft)) ||
+           (dev && !config_file_read_fd(cft, dev, offset, size,
+                                        offset2, size2, checksum_fn, checksum)))
                goto_out;
 
        /*
@@ -72,12 +69,13 @@ const char *text_vgname_import(const struct format_type *fmt,
        }
 
       out:
-       destroy_config_tree(cft);
+       config_file_destroy(cft);
        return vgname;
 }
 
 struct volume_group *text_vg_import_fd(struct format_instance *fid,
                                       const char *file,
+                                      int single_device,
                                       struct device *dev,
                                       off_t offset, uint32_t size,
                                       off_t offset2, uint32_t size2,
@@ -86,7 +84,7 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
                                       time_t *when, char **desc)
 {
        struct volume_group *vg = NULL;
-       struct config_tree *cft;
+       struct dm_config_tree *cft;
        struct text_vg_version_ops **vsn;
 
        _init_text_import();
@@ -94,12 +92,12 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
        *desc = NULL;
        *when = 0;
 
-       if (!(cft = create_config_tree(file, 0)))
+       if (!(cft = config_file_open(file, 0)))
                return_NULL;
 
-       if ((!dev && !read_config_file(cft)) ||
-           (dev && !read_config_fd(cft, dev, offset, size,
-                                   offset2, size2, checksum_fn, checksum))) {
+       if ((!dev && !config_file_read(cft)) ||
+           (dev && !config_file_read_fd(cft, dev, offset, size,
+                                        offset2, size2, checksum_fn, checksum))) {
                log_error("Couldn't read volume group metadata.");
                goto out;
        }
@@ -111,7 +109,7 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
                if (!(*vsn)->check_version(cft))
                        continue;
 
-               if (!(vg = (*vsn)->read_vg(fid, cft, 0)))
+               if (!(vg = (*vsn)->read_vg(fid, cft, single_device)))
                        goto_out;
 
                (*vsn)->read_desc(vg->vgmem, cft, when, desc);
@@ -119,7 +117,7 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
        }
 
       out:
-       destroy_config_tree(cft);
+       config_file_destroy(cft);
        return vg;
 }
 
@@ -127,22 +125,19 @@ struct volume_group *text_vg_import_file(struct format_instance *fid,
                                         const char *file,
                                         time_t *when, char **desc)
 {
-       return text_vg_import_fd(fid, file, NULL, (off_t)0, 0, (off_t)0, 0, NULL, 0,
+       return text_vg_import_fd(fid, file, 0, NULL, (off_t)0, 0, (off_t)0, 0, NULL, 0,
                                 when, desc);
 }
 
-struct volume_group *import_vg_from_buffer(const char *buf,
-                                           struct format_instance *fid)
+struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft,
+                                               struct format_instance *fid)
 {
        struct volume_group *vg = NULL;
-       struct config_tree *cft;
        struct text_vg_version_ops **vsn;
+       int vg_missing;
 
        _init_text_import();
 
-       if (!(cft = create_config_tree_from_string(fid->fmt->cmd, buf)))
-               return_NULL;
-
        for (vsn = &_text_vsn_list[0]; *vsn; vsn++) {
                if (!(*vsn)->check_version(cft))
                        continue;
@@ -152,9 +147,14 @@ struct volume_group *import_vg_from_buffer(const char *buf,
                 */
                if (!(vg = (*vsn)->read_vg(fid, cft, 1)))
                        stack;
+               else if ((vg_missing = vg_missing_pv_count(vg))) {
+                       log_verbose("There are %d physical volumes missing.",
+                                   vg_missing);
+                       vg_mark_partial_lvs(vg, 1);
+                       /* FIXME: move this code inside read_vg() */
+               }
                break;
        }
 
-       destroy_config_tree(cft);
        return vg;
 }
index e5e83d46a0a3938e24ed3dbc254834577903365a..dff70f711a0a676d1e7e4de509a072ff3126b9ce 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
 #include "display.h"
 #include "toolcontext.h"
 #include "lvmcache.h"
+#include "lvmetad.h"
 #include "lv_alloc.h"
 #include "pv_alloc.h"
 #include "segtype.h"
 #include "text_import.h"
 #include "defaults.h"
 
-typedef int (*section_fn) (struct format_instance * fid, struct dm_pool * mem,
-                          struct volume_group * vg, const struct config_node * pvn,
-                          const struct config_node * vgn,
+typedef int (*section_fn) (struct format_instance * fid,
+                          struct volume_group * vg, const struct dm_config_node * pvn,
+                          const struct dm_config_node * vgn,
                           struct dm_hash_table * pv_hash,
                           struct dm_hash_table * lv_hash,
                           unsigned *scan_done_once,
                           unsigned report_missing_devices);
 
 #define _read_int32(root, path, result) \
-       get_config_uint32(root, path, (uint32_t *) result)
+       dm_config_get_uint32(root, path, (uint32_t *) result)
 
 #define _read_uint32(root, path, result) \
-       get_config_uint32(root, path, result)
+       dm_config_get_uint32(root, path, result)
 
-#define _read_int64(root, path, result) \
-       get_config_uint64(root, path, result)
+#define _read_uint64(root, path, result) \
+       dm_config_get_uint64(root, path, result)
 
 /*
  * Logs an attempt to read an invalid format file.
@@ -54,21 +55,25 @@ static void _invalid_format(const char *str)
  * Checks that the config file contains vg metadata, and that it
  * we recognise the version number,
  */
-static int _check_version(const struct config_tree *cft)
+static int _vsn1_check_version(const struct dm_config_tree *cft)
 {
-       const struct config_node *cn;
-       const struct config_value *cv;
+       const struct dm_config_node *cn;
+       const struct dm_config_value *cv;
+
+       // TODO if this is pvscan --cache, we want this check back.
+       if (lvmetad_active())
+               return 1;
 
        /*
         * Check the contents field.
         */
-       if (!(cn = find_config_node(cft->root, CONTENTS_FIELD))) {
+       if (!(cn = dm_config_find_node(cft->root, CONTENTS_FIELD))) {
                _invalid_format("missing contents field");
                return 0;
        }
 
        cv = cn->v;
-       if (!cv || cv->type != CFG_STRING || strcmp(cv->v.str, CONTENTS_VALUE)) {
+       if (!cv || cv->type != DM_CFG_STRING || strcmp(cv->v.str, CONTENTS_VALUE)) {
                _invalid_format("unrecognised contents field");
                return 0;
        }
@@ -76,13 +81,13 @@ static int _check_version(const struct config_tree *cft)
        /*
         * Check the version number.
         */
-       if (!(cn = find_config_node(cft->root, FORMAT_VERSION_FIELD))) {
+       if (!(cn = dm_config_find_node(cft->root, FORMAT_VERSION_FIELD))) {
                _invalid_format("missing version number");
                return 0;
        }
 
        cv = cn->v;
-       if (!cv || cv->type != CFG_INT || cv->v.i != FORMAT_VERSION_VALUE) {
+       if (!cv || cv->type != DM_CFG_INT || cv->v.i != FORMAT_VERSION_VALUE) {
                _invalid_format("unrecognised version number");
                return 0;
        }
@@ -106,22 +111,16 @@ static int _is_converting(struct logical_volume *lv)
        return 0;
 }
 
-static int _read_id(struct id *id, const struct config_node *cn, const char *path)
+static int _read_id(struct id *id, const struct dm_config_node *cn, const char *path)
 {
-       const struct config_value *cv;
+       const char *uuid;
 
-       if (!(cn = find_config_node(cn, path))) {
+       if (!dm_config_get_str(cn, path, &uuid)) {
                log_error("Couldn't find uuid.");
                return 0;
        }
 
-       cv = cn->v;
-       if (!cv || !cv->v.str) {
-               log_error("uuid must be a string.");
-               return 0;
-       }
-
-       if (!id_read_format(id, cv->v.str)) {
+       if (!id_read_format(id, uuid)) {
                log_error("Invalid uuid.");
                return 0;
        }
@@ -129,23 +128,23 @@ static int _read_id(struct id *id, const struct config_node *cn, const char *pat
        return 1;
 }
 
-static int _read_flag_config(const struct config_node *n, uint64_t *status, int type)
+static int _read_flag_config(const struct dm_config_node *n, uint64_t *status, int type)
 {
-       const struct config_node *cn;
+       const struct dm_config_value *cv;
        *status = 0;
 
-       if (!(cn = find_config_node(n, "status"))) {
+       if (!dm_config_get_list(n, "status", &cv)) {
                log_error("Could not find status flags.");
                return 0;
        }
 
-       if (!(read_flags(status, type | STATUS_FLAG, cn->v))) {
+       if (!(read_flags(status, type | STATUS_FLAG, cv))) {
                log_error("Could not read status flags.");
                return 0;
        }
 
-       if ((cn = find_config_node(n, "flags"))) {
-               if (!(read_flags(status, type, cn->v))) {
+       if (dm_config_get_list(n, "flags", &cv)) {
+               if (!(read_flags(status, type, cv))) {
                        log_error("Could not read flags.");
                        return 0;
                }
@@ -154,17 +153,18 @@ static int _read_flag_config(const struct config_node *n, uint64_t *status, int
        return 1;
 }
 
-static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
-                   struct volume_group *vg, const struct config_node *pvn,
-                   const struct config_node *vgn __attribute__((unused)),
+static int _read_pv(struct format_instance *fid,
+                   struct volume_group *vg, const struct dm_config_node *pvn,
+                   const struct dm_config_node *vgn __attribute__((unused)),
                    struct dm_hash_table *pv_hash,
                    struct dm_hash_table *lv_hash __attribute__((unused)),
                    unsigned *scan_done_once,
                    unsigned report_missing_devices)
 {
+       struct dm_pool *mem = vg->vgmem;
        struct physical_volume *pv;
        struct pv_list *pvl;
-       const struct config_node *cn;
+       const struct dm_config_value *cv;
        uint64_t size;
 
        if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl))) ||
@@ -190,10 +190,13 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
                return 0;
        }
 
+        pv->is_labelled = 1; /* All format_text PVs are labelled. */
+
        /*
         * Convert the uuid into a device.
         */
-       if (!(pv->dev = device_from_pvid(fid->fmt->cmd, &pv->id, scan_done_once))) {
+       if (!(pv->dev = lvmcache_device_from_pvid(fid->fmt->cmd, &pv->id, scan_done_once,
+                                         &pv->label_sector))) {
                char buffer[64] __attribute__((aligned(8)));
 
                if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
@@ -214,13 +217,18 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
                return 0;
        }
 
-       if (!pv->dev)
+       /* TODO is the !lvmetad_active() too coarse here? */
+       if (!pv->dev && !lvmetad_active())
                pv->status |= MISSING_PV;
 
        /* Late addition */
-       _read_int64(pvn, "dev_size", &pv->size);
+       if (dm_config_has_node(pvn, "dev_size") &&
+           !_read_uint64(pvn, "dev_size", &pv->size)) {
+               log_error("Couldn't read dev size for physical volume.");
+               return 0;
+       }
 
-       if (!_read_int64(pvn, "pe_start", &pv->pe_start)) {
+       if (!_read_uint64(pvn, "pe_start", &pv->pe_start)) {
                log_error("Couldn't read extent size for physical volume.");
                return 0;
        }
@@ -235,8 +243,8 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
        dm_list_init(&pv->segments);
 
        /* Optional tags */
-       if ((cn = find_config_node(pvn, "tags")) &&
-           !(read_tags(mem, &pv->tags, cn->v))) {
+       if (dm_config_get_list(pvn, "tags", &cv) &&
+           !(read_tags(mem, &pv->tags, cv))) {
                log_error("Couldn't read tags for physical volume %s in %s.",
                          pv_dev_name(pv), vg->name);
                return 0;
@@ -257,14 +265,10 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
                log_verbose("Fixing up missing size (%s) "
                            "for PV %s", display_size(fid->fmt->cmd, pv->size),
                            pv_dev_name(pv));
-               if (vg) {
-                       size = pv->pe_count * (uint64_t) vg->extent_size +
-                              pv->pe_start;
-                       if (size > pv->size)
-                               log_warn("WARNING: Physical Volume %s is too "
-                                        "large for underlying device",
-                                        pv_dev_name(pv));
-               }
+               size = pv->pe_count * (uint64_t) vg->extent_size + pv->pe_start;
+               if (size > pv->size)
+                       log_warn("WARNING: Physical Volume %s is too large "
+                                "for underlying device", pv_dev_name(pv));
        }
 
        if (!alloc_pv_segment_whole_pv(mem, pv))
@@ -292,14 +296,14 @@ static void _insert_segment(struct logical_volume *lv, struct lv_segment *seg)
        dm_list_add(&lv->segments, &seg->list);
 }
 
-static int _read_segment(struct dm_pool *mem, struct volume_group *vg,
-                        struct logical_volume *lv, const struct config_node *sn,
+static int _read_segment(struct logical_volume *lv, const struct dm_config_node *sn,
                         struct dm_hash_table *pv_hash)
 {
+       struct dm_pool *mem = lv->vg->vgmem;
        uint32_t area_count = 0u;
        struct lv_segment *seg;
-       const struct config_node *cn, *sn_child = sn->child;
-       const struct config_value *cv;
+       const struct dm_config_node *sn_child = sn->child;
+       const struct dm_config_value *cv;
        uint32_t start_extent, extent_count;
        struct segment_type *segtype;
        const char *segtype_str;
@@ -323,24 +327,20 @@ static int _read_segment(struct dm_pool *mem, struct volume_group *vg,
 
        segtype_str = "striped";
 
-       if ((cn = find_config_node(sn_child, "type"))) {
-               cv = cn->v;
-               if (!cv || !cv->v.str) {
-                       log_error("Segment type must be a string.");
-                       return 0;
-               }
-               segtype_str = cv->v.str;
+       if (!dm_config_get_str(sn_child, "type", &segtype_str)) {
+               log_error("Segment type must be a string.");
+               return 0;
        }
 
-       if (!(segtype = get_segtype_from_string(vg->cmd, segtype_str)))
+       if (!(segtype = get_segtype_from_string(lv->vg->cmd, segtype_str)))
                return_0;
 
        if (segtype->ops->text_import_area_count &&
            !segtype->ops->text_import_area_count(sn_child, &area_count))
                return_0;
 
-       if (!(seg = alloc_lv_segment(mem, segtype, lv, start_extent,
-                                    extent_count, 0, 0, NULL, area_count,
+       if (!(seg = alloc_lv_segment(segtype, lv, start_extent,
+                                    extent_count, 0, 0, NULL, NULL, area_count,
                                     extent_count, 0, 0, 0, NULL))) {
                log_error("Segment allocation failed");
                return 0;
@@ -351,10 +351,10 @@ static int _read_segment(struct dm_pool *mem, struct volume_group *vg,
                return_0;
 
        /* Optional tags */
-       if ((cn = find_config_node(sn_child, "tags")) &&
-           !(read_tags(mem, &seg->tags, cn->v))) {
+       if (dm_config_get_list(sn_child, "tags", &cv) &&
+           !(read_tags(mem, &seg->tags, cv))) {
                log_error("Couldn't read tags for a segment of %s/%s.",
-                         vg->name, lv->name);
+                         lv->vg->name, lv->name);
                return 0;
        }
 
@@ -366,34 +366,36 @@ static int _read_segment(struct dm_pool *mem, struct volume_group *vg,
        if (seg_is_mirrored(seg))
                lv->status |= MIRRORED;
 
+       if (seg_is_raid(seg))
+               lv->status |= RAID;
+
        if (seg_is_virtual(seg))
                lv->status |= VIRTUAL;
 
-       if (_is_converting(lv))
+       if (!seg_is_raid(seg) && _is_converting(lv))
                lv->status |= CONVERTING;
 
        return 1;
 }
 
-int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
-                     const struct config_node *cn, struct dm_hash_table *pv_hash,
+int text_import_areas(struct lv_segment *seg, const struct dm_config_node *sn,
+                     const struct dm_config_value *cv, struct dm_hash_table *pv_hash,
                      uint64_t status)
 {
        unsigned int s;
-       const struct config_value *cv;
        struct logical_volume *lv1;
        struct physical_volume *pv;
-       const char *seg_name = config_parent_name(sn);
+       const char *seg_name = dm_config_parent_name(sn);
 
        if (!seg->area_count) {
                log_error("Zero areas not allowed for segment %s", seg_name);
                return 0;
        }
 
-       for (cv = cn->v, s = 0; cv && s < seg->area_count; s++, cv = cv->next) {
+       for (s = 0; cv && s < seg->area_count; s++, cv = cv->next) {
 
                /* first we read the pv */
-               if (cv->type != CFG_STRING) {
+               if (cv->type != DM_CFG_STRING) {
                        log_error("Bad volume name in areas array for segment %s.", seg_name);
                        return 0;
                }
@@ -403,7 +405,7 @@ int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
                        return 0;
                }
 
-               if (cv->next->type != CFG_INT) {
+               if (cv->next->type != DM_CFG_INT) {
                        log_error("Bad offset in areas array for segment %s.", seg_name);
                        return 0;
                }
@@ -439,11 +441,10 @@ int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
        return 1;
 }
 
-static int _read_segments(struct dm_pool *mem, struct volume_group *vg,
-                         struct logical_volume *lv, const struct config_node *lvn,
+static int _read_segments(struct logical_volume *lv, const struct dm_config_node *lvn,
                          struct dm_hash_table *pv_hash)
 {
-       const struct config_node *sn;
+       const struct dm_config_node *sn;
        int count = 0, seg_count;
 
        for (sn = lvn; sn; sn = sn->sib) {
@@ -452,7 +453,7 @@ static int _read_segments(struct dm_pool *mem, struct volume_group *vg,
                 * All sub-sections are assumed to be segments.
                 */
                if (!sn->v) {
-                       if (!_read_segment(mem, vg, lv, sn, pv_hash))
+                       if (!_read_segment(lv, sn, pv_hash))
                                return_0;
 
                        count++;
@@ -492,16 +493,19 @@ static int _read_segments(struct dm_pool *mem, struct volume_group *vg,
 }
 
 static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
-                        struct dm_pool *mem,
-                        struct volume_group *vg, const struct config_node *lvn,
-                        const struct config_node *vgn __attribute__((unused)),
+                        struct volume_group *vg, const struct dm_config_node *lvn,
+                        const struct dm_config_node *vgn __attribute__((unused)),
                         struct dm_hash_table *pv_hash __attribute__((unused)),
                         struct dm_hash_table *lv_hash,
                         unsigned *scan_done_once __attribute__((unused)),
                         unsigned report_missing_devices __attribute__((unused)))
 {
+       struct dm_pool *mem = vg->vgmem;
        struct logical_volume *lv;
-       const struct config_node *cn;
+       const char *lv_alloc;
+       const struct dm_config_value *cv;
+       const char *hostname;
+       uint64_t timestamp = 0;
 
        if (!(lv = alloc_lv(mem)))
                return_0;
@@ -520,17 +524,28 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
                return 0;
        }
 
-       lv->alloc = ALLOC_INHERIT;
-       if ((cn = find_config_node(lvn, "allocation_policy"))) {
-               const struct config_value *cv = cn->v;
-               if (!cv || !cv->v.str) {
-                       log_error("allocation_policy must be a string.");
+       if (dm_config_has_node(lvn, "creation_time")) {
+               if (!_read_uint64(lvn, "creation_time", &timestamp)) {
+                       log_error("Invalid creation_time for logical volume %s.",
+                                 lv->name);
+                       return 0;
+               }
+               if (!dm_config_get_str(lvn, "creation_host", &hostname)) {
+                       log_error("Couldn't read creation_host for logical volume %s.",
+                                 lv->name);
                        return 0;
                }
+       } else if (dm_config_has_node(lvn, "creation_host")) {
+               log_error("Missing creation_time for logical volume %s.",
+                         lv->name);
+               return 0;
+       }
 
-               lv->alloc = get_alloc_from_string(cv->v.str);
+       lv->alloc = ALLOC_INHERIT;
+       if (dm_config_get_str(lvn, "allocation_policy", &lv_alloc)) {
+               lv->alloc = get_alloc_from_string(lv_alloc);
                if (lv->alloc == ALLOC_INVALID) {
-                       log_warn("WARNING: Ignoring unrecognised allocation policy %s for LV %s", cv->v.str, lv->name);
+                       log_warn("WARNING: Ignoring unrecognised allocation policy %s for LV %s", lv_alloc, lv->name);
                        lv->alloc = ALLOC_INHERIT;
                }
        }
@@ -552,8 +567,8 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
        }
 
        /* Optional tags */
-       if ((cn = find_config_node(lvn, "tags")) &&
-           !(read_tags(mem, &lv->tags, cn->v))) {
+       if (dm_config_get_list(lvn, "tags", &cv) &&
+           !(read_tags(mem, &lv->tags, cv))) {
                log_error("Couldn't read tags for logical volume %s/%s.",
                          vg->name, lv->name);
                return 0;
@@ -562,13 +577,18 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
        if (!dm_hash_insert(lv_hash, lv->name, lv))
                return_0;
 
-       return link_lv_to_vg(vg, lv);
+       if (!link_lv_to_vg(vg, lv))
+               return_0;
+
+       if (timestamp && !lv_set_creation(lv, hostname, timestamp))
+               return_0;
+
+       return 1;
 }
 
 static int _read_lvsegs(struct format_instance *fid __attribute__((unused)),
-                       struct dm_pool *mem,
-                       struct volume_group *vg, const struct config_node *lvn,
-                       const struct config_node *vgn __attribute__((unused)),
+                       struct volume_group *vg, const struct dm_config_node *lvn,
+                       const struct dm_config_node *vgn __attribute__((unused)),
                        struct dm_hash_table *pv_hash,
                        struct dm_hash_table *lv_hash,
                        unsigned *scan_done_once __attribute__((unused)),
@@ -595,7 +615,7 @@ static int _read_lvsegs(struct format_instance *fid __attribute__((unused)),
 
        memcpy(&lv->lvid.id[0], &lv->vg->id, sizeof(lv->lvid.id[0]));
 
-       if (!_read_segments(mem, vg, lv, lvn, pv_hash))
+       if (!_read_segments(lv, lvn, pv_hash))
                return_0;
 
        lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size;
@@ -620,18 +640,17 @@ static int _read_lvsegs(struct format_instance *fid __attribute__((unused)),
 
 static int _read_sections(struct format_instance *fid,
                          const char *section, section_fn fn,
-                         struct dm_pool *mem,
-                         struct volume_group *vg, const struct config_node *vgn,
+                         struct volume_group *vg, const struct dm_config_node *vgn,
                          struct dm_hash_table *pv_hash,
                          struct dm_hash_table *lv_hash,
                          int optional,
                          unsigned *scan_done_once)
 {
-       const struct config_node *n;
+       const struct dm_config_node *n;
        /* Only report missing devices when doing a scan */
        unsigned report_missing_devices = scan_done_once ? !*scan_done_once : 1;
 
-       if (!(n = find_config_node(vgn, section))) {
+       if (!dm_config_get_section(vgn, section, &n)) {
                if (!optional) {
                        log_error("Couldn't find section '%s'.", section);
                        return 0;
@@ -641,7 +660,7 @@ static int _read_sections(struct format_instance *fid,
        }
 
        for (n = n->child; n; n = n->sib) {
-               if (!fn(fid, mem, vg, n, vgn, pv_hash, lv_hash,
+               if (!fn(fid, vg, n, vgn, pv_hash, lv_hash,
                        scan_done_once, report_missing_devices))
                        return_0;
        }
@@ -650,51 +669,53 @@ static int _read_sections(struct format_instance *fid,
 }
 
 static struct volume_group *_read_vg(struct format_instance *fid,
-                                    const struct config_tree *cft,
+                                    const struct dm_config_tree *cft,
                                     unsigned use_cached_pvs)
 {
-       const struct config_node *vgn, *cn;
+       const struct dm_config_node *vgn;
+       const struct dm_config_value *cv;
+       const char *str;
        struct volume_group *vg;
        struct dm_hash_table *pv_hash = NULL, *lv_hash = NULL;
-       struct dm_pool *mem = dm_pool_create("lvm2 vg_read", VG_MEMPOOL_CHUNK);
        unsigned scan_done_once = use_cached_pvs;
 
-       if (!mem)
-               return_NULL;
-
        /* skip any top-level values */
        for (vgn = cft->root; (vgn && vgn->v); vgn = vgn->sib)
                ;
 
        if (!vgn) {
                log_error("Couldn't find volume group in file.");
-               goto bad;
+               return NULL;
        }
 
-       if (!(vg = dm_pool_zalloc(mem, sizeof(*vg))))
-               goto_bad;
-
-       vg->vgmem = mem;
-       vg->cmd = fid->fmt->cmd;
-
-       /* FIXME Determine format type from file contents */
-       /* eg Set to instance of fmt1 here if reading a format1 backup? */
-       vg->fid = fid;
+       if (!(vg = alloc_vg("read_vg", fid->fmt->cmd, vgn->key)))
+               return_NULL;
 
-       if (!(vg->name = dm_pool_strdup(mem, vgn->key)))
+       if (!(vg->system_id = dm_pool_zalloc(vg->vgmem, NAME_LEN + 1)))
                goto_bad;
 
-       if (!(vg->system_id = dm_pool_zalloc(mem, NAME_LEN)))
-               goto_bad;
+       /*
+        * The pv hash memorises the pv section names -> pv
+        * structures.
+        */
+       if (!(pv_hash = dm_hash_create(64))) {
+               log_error("Couldn't create pv hash table.");
+               goto bad;
+       }
+
+       /*
+        * The lv hash memorises the lv section names -> lv
+        * structures.
+        */
+       if (!(lv_hash = dm_hash_create(1024))) {
+               log_error("Couldn't create lv hash table.");
+               goto bad;
+       }
 
        vgn = vgn->child;
 
-       if ((cn = find_config_node(vgn, "system_id")) && cn->v) {
-               if (!cn->v->v.str) {
-                       log_error("system_id must be a string");
-                       goto bad;
-               }
-               strncpy(vg->system_id, cn->v->v.str, NAME_LEN);
+       if (dm_config_get_str(vgn, "system_id", &str)) {
+               strncpy(vg->system_id, str, NAME_LEN);
        }
 
        if (!_read_id(&vg->id, vgn, "id")) {
@@ -737,17 +758,10 @@ static struct volume_group *_read_vg(struct format_instance *fid,
                goto bad;
        }
 
-       vg->alloc = ALLOC_NORMAL;
-       if ((cn = find_config_node(vgn, "allocation_policy"))) {
-               const struct config_value *cv = cn->v;
-               if (!cv || !cv->v.str) {
-                       log_error("allocation_policy must be a string.");
-                       goto bad;
-               }
-
-               vg->alloc = get_alloc_from_string(cv->v.str);
+       if (dm_config_get_str(vgn, "allocation_policy", &str)) {
+               vg->alloc = get_alloc_from_string(str);
                if (vg->alloc == ALLOC_INVALID) {
-                       log_warn("WARNING: Ignoring unrecognised allocation policy %s for VG %s", cv->v.str, vg->name);
+                       log_warn("WARNING: Ignoring unrecognised allocation policy %s for VG %s", str, vg->name);
                        vg->alloc = ALLOC_NORMAL;
                }
        }
@@ -756,51 +770,28 @@ static struct volume_group *_read_vg(struct format_instance *fid,
                vg->mda_copies = DEFAULT_VGMETADATACOPIES;
        }
 
-       /*
-        * The pv hash memorises the pv section names -> pv
-        * structures.
-        */
-       if (!(pv_hash = dm_hash_create(32))) {
-               log_error("Couldn't create hash table.");
-               goto bad;
-       }
-
-       dm_list_init(&vg->pvs);
-       if (!_read_sections(fid, "physical_volumes", _read_pv, mem, vg,
+       if (!_read_sections(fid, "physical_volumes", _read_pv, vg,
                            vgn, pv_hash, lv_hash, 0, &scan_done_once)) {
                log_error("Couldn't find all physical volumes for volume "
                          "group %s.", vg->name);
                goto bad;
        }
 
-       dm_list_init(&vg->lvs);
-       dm_list_init(&vg->tags);
-       dm_list_init(&vg->removed_pvs);
-
        /* Optional tags */
-       if ((cn = find_config_node(vgn, "tags")) &&
-           !(read_tags(mem, &vg->tags, cn->v))) {
+       if (dm_config_get_list(vgn, "tags", &cv) &&
+           !(read_tags(vg->vgmem, &vg->tags, cv))) {
                log_error("Couldn't read tags for volume group %s.", vg->name);
                goto bad;
        }
 
-       /*
-        * The lv hash memorises the lv section names -> lv
-        * structures.
-        */
-       if (!(lv_hash = dm_hash_create(32))) {
-               log_error("Couldn't create hash table.");
-               goto bad;
-       }
-
-       if (!_read_sections(fid, "logical_volumes", _read_lvnames, mem, vg,
+       if (!_read_sections(fid, "logical_volumes", _read_lvnames, vg,
                            vgn, pv_hash, lv_hash, 1, NULL)) {
                log_error("Couldn't read all logical volume names for volume "
                          "group %s.", vg->name);
                goto bad;
        }
 
-       if (!_read_sections(fid, "logical_volumes", _read_lvsegs, mem, vg,
+       if (!_read_sections(fid, "logical_volumes", _read_lvsegs, vg,
                            vgn, pv_hash, lv_hash, 1, NULL)) {
                log_error("Couldn't read all logical volumes for "
                          "volume group %s.", vg->name);
@@ -816,6 +807,10 @@ static struct volume_group *_read_vg(struct format_instance *fid,
        dm_hash_destroy(pv_hash);
        dm_hash_destroy(lv_hash);
 
+       /* FIXME Determine format type from file contents */
+       /* eg Set to instance of fmt1 here if reading a format1 backup? */
+       vg_set_fid(vg, fid);
+
        /*
         * Finished.
         */
@@ -828,38 +823,38 @@ static struct volume_group *_read_vg(struct format_instance *fid,
        if (lv_hash)
                dm_hash_destroy(lv_hash);
 
-       dm_pool_destroy(mem);
+       release_vg(vg);
        return NULL;
 }
 
 static void _read_desc(struct dm_pool *mem,
-                      const struct config_tree *cft, time_t *when, char **desc)
+                      const struct dm_config_tree *cft, time_t *when, char **desc)
 {
        const char *d;
        unsigned int u = 0u;
        int old_suppress;
 
        old_suppress = log_suppress(1);
-       d = find_config_str(cft->root, "description", "");
+       d = dm_config_find_str_allow_empty(cft->root, "description", "");
        log_suppress(old_suppress);
        *desc = dm_pool_strdup(mem, d);
 
-       get_config_uint32(cft->root, "creation_time", &u);
+       (void) dm_config_get_uint32(cft->root, "creation_time", &u);
        *when = u;
 }
 
 static const char *_read_vgname(const struct format_type *fmt,
-                               const struct config_tree *cft, struct id *vgid,
+                               const struct dm_config_tree *cft, struct id *vgid,
                                uint64_t *vgstatus, char **creation_host)
 {
-       const struct config_node *vgn;
+       const struct dm_config_node *vgn;
        struct dm_pool *mem = fmt->cmd->mem;
        char *vgname;
        int old_suppress;
 
        old_suppress = log_suppress(2);
        *creation_host = dm_pool_strdup(mem,
-                                       find_config_str(cft->root,
+                                       dm_config_find_str_allow_empty(cft->root,
                                                        "creation_host", ""));
        log_suppress(old_suppress);
 
@@ -891,7 +886,7 @@ static const char *_read_vgname(const struct format_type *fmt,
 }
 
 static struct text_vg_version_ops _vsn1_ops = {
-       .check_version = _check_version,
+       .check_version = _vsn1_check_version,
        .read_vg = _read_vg,
        .read_desc = _read_desc,
        .read_vgname = _read_vgname,
index a3141e07d108b0b2a5614e0648c8f2936da582aa..1a9856d38e3a74ab7d22251bb5899bec8c5142d8 100644 (file)
 #include "metadata.h"
 #include "uuid.h"
 
-/* On disk */
-struct disk_locn {
-       uint64_t offset;        /* Offset in bytes to start sector */
-       uint64_t size;          /* Bytes */
-} __attribute__ ((packed));
-
-/* Data areas (holding PEs) */
-struct data_area_list {
-       struct dm_list list;
-       struct disk_locn disk_locn;
-};
+/* disk_locn and data_area_list are defined in format-text.h */
 
 /* Fields with the suffix _xl should be xlate'd wherever they appear */
 /* On disk */
index 76d42db62d5c184f339c9af0f3d3cc8d2766542d..b0f0732aac00e8da4b4514aa06b9cd4757219441 100644 (file)
@@ -61,13 +61,13 @@ bad:
        return_NULL;
 }
 
-int read_tags(struct dm_pool *mem, struct dm_list *tags, const struct config_value *cv)
+int read_tags(struct dm_pool *mem, struct dm_list *tags, const struct dm_config_value *cv)
 {
-       if (cv->type == CFG_EMPTY_ARRAY)
+       if (cv->type == DM_CFG_EMPTY_ARRAY)
                return 1;
 
        while (cv) {
-               if (cv->type != CFG_STRING) {
+               if (cv->type != DM_CFG_STRING) {
                        log_error("Found a tag that is not a string");
                        return 0;
                }
index 39a6916457335e87e1fb98d551875f2d2c1b17a8..991203c25f949a185953283bf317a8f120239a9e 100644 (file)
@@ -24,7 +24,7 @@
 
 struct formatter;
 struct lv_segment;
-struct config_node;
+struct dm_config_node;
 
 int out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
     __attribute__ ((format(printf, 3, 4)));
@@ -35,7 +35,7 @@ int out_hint(struct formatter *f, const char *fmt, ...)
 int out_text(struct formatter *f, const char *fmt, ...)
     __attribute__ ((format(printf, 2, 3)));
 
-int out_config_node(struct formatter *f, const struct config_node *cn);
+int out_config_node(struct formatter *f, const struct dm_config_node *cn);
 
 int out_areas(struct formatter *f, const struct lv_segment *seg,
              const char *type);
index 99d222f1f2bf7b01ad276861cc4e7056574337e1..faebc07a14742e04dbc64be2133cf43137972a85 100644 (file)
 #define _LVM_TEXT_IMPORT_H
 
 struct lv_segment;
-struct config_node;
+struct dm_config_node;
 
-int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
-                     const struct config_node *cn, struct dm_hash_table *pv_hash,
+int text_import_areas(struct lv_segment *seg, const struct dm_config_node *sn,
+                     const struct dm_config_value *cv, struct dm_hash_table *pv_hash,
                      uint64_t status);
 
 #endif
index e459cdef4a79de9627c6a8f3871bbd8fec4ab942..f53aa0d55852798bf1a3fac31d6a61fd3fb241ec 100644 (file)
@@ -35,15 +35,41 @@ static int _text_can_handle(struct labeller *l __attribute__((unused)),
        return 0;
 }
 
+struct _da_setup_baton {
+       struct disk_locn *pvh_dlocn_xl;
+       struct device *dev;
+};
+
+static int _da_setup(struct disk_locn *da, void *baton)
+{
+       struct _da_setup_baton *p = baton;
+       p->pvh_dlocn_xl->offset = xlate64(da->offset);
+       p->pvh_dlocn_xl->size = xlate64(da->size);
+       p->pvh_dlocn_xl++;
+       return 1;
+}
+
+static int _mda_setup(struct metadata_area *mda, void *baton)
+{
+       struct _da_setup_baton *p = baton;
+       struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
+
+       if (mdac->area.dev != p->dev)
+               return 1;
+
+       p->pvh_dlocn_xl->offset = xlate64(mdac->area.start);
+       p->pvh_dlocn_xl->size = xlate64(mdac->area.size);
+       p->pvh_dlocn_xl++;
+
+       return 1;
+}
+
 static int _text_write(struct label *label, void *buf)
 {
        struct label_header *lh = (struct label_header *) buf;
        struct pv_header *pvhdr;
        struct lvmcache_info *info;
-       struct disk_locn *pvh_dlocn_xl;
-       struct metadata_area *mda;
-       struct mda_context *mdac;
-       struct data_area_list *da;
+       struct _da_setup_baton baton;
        char buffer[64] __attribute__((aligned(8)));
        int da1, mda1, mda2;
 
@@ -52,45 +78,33 @@ static int _text_write(struct label *label, void *buf)
 
        strncpy((char *)lh->type, label->type, sizeof(label->type));
 
-       pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl));
+       pvhdr = (struct pv_header *) ((char *) buf + xlate32(lh->offset_xl));
        info = (struct lvmcache_info *) label->info;
-       pvhdr->device_size_xl = xlate64(info->device_size);
-       memcpy(pvhdr->pv_uuid, &info->dev->pvid, sizeof(struct id));
+       pvhdr->device_size_xl = xlate64(lvmcache_device_size(info));
+       memcpy(pvhdr->pv_uuid, &lvmcache_device(info)->pvid, sizeof(struct id));
        if (!id_write_format((const struct id *)pvhdr->pv_uuid, buffer,
                             sizeof(buffer))) {
                stack;
                buffer[0] = '\0';
        }
 
-       pvh_dlocn_xl = &pvhdr->disk_areas_xl[0];
+       baton.dev = lvmcache_device(info);
 
        /* List of data areas (holding PEs) */
-       dm_list_iterate_items(da, &info->das) {
-               pvh_dlocn_xl->offset = xlate64(da->disk_locn.offset);
-               pvh_dlocn_xl->size = xlate64(da->disk_locn.size);
-               pvh_dlocn_xl++;
-       }
+       baton.pvh_dlocn_xl = &pvhdr->disk_areas_xl[0];
+       lvmcache_foreach_da(info, _da_setup, &baton);
 
        /* NULL-termination */
-       pvh_dlocn_xl->offset = xlate64(UINT64_C(0));
-       pvh_dlocn_xl->size = xlate64(UINT64_C(0));
-       pvh_dlocn_xl++;
+       baton.pvh_dlocn_xl->offset = xlate64(UINT64_C(0));
+       baton.pvh_dlocn_xl->size = xlate64(UINT64_C(0));
+       baton.pvh_dlocn_xl++;
 
        /* List of metadata area header locations */
-       dm_list_iterate_items(mda, &info->mdas) {
-               mdac = (struct mda_context *) mda->metadata_locn;
-
-               if (mdac->area.dev != info->dev)
-                       continue;
-
-               pvh_dlocn_xl->offset = xlate64(mdac->area.start);
-               pvh_dlocn_xl->size = xlate64(mdac->area.size);
-               pvh_dlocn_xl++;
-       }
+       lvmcache_foreach_mda(info, _mda_setup, &baton);
 
        /* NULL-termination */
-       pvh_dlocn_xl->offset = xlate64(UINT64_C(0));
-       pvh_dlocn_xl->size = xlate64(UINT64_C(0));
+       baton.pvh_dlocn_xl->offset = xlate64(UINT64_C(0));
+       baton.pvh_dlocn_xl->size = xlate64(UINT64_C(0));
 
        /* Create debug message with da and mda locations */
        if (xlate64(pvhdr->disk_areas_xl[0].offset) ||
@@ -113,7 +127,7 @@ static int _text_write(struct label *label, void *buf)
                  "%s%.*" PRIu64 "%s%.*" PRIu64 "%s"
                  "%s%.*" PRIu64 "%s%.*" PRIu64 "%s"
                  "%s%.*" PRIu64 "%s%.*" PRIu64 "%s",
-                 dev_name(info->dev), buffer, info->device_size, 
+                 dev_name(lvmcache_device(info)), buffer, lvmcache_device_size(info),
                  (da1 > -1) ? " da1 (" : "",
                  (da1 > -1) ? 1 : 0,
                  (da1 > -1) ? xlate64(pvhdr->disk_areas_xl[da1].offset) >> SECTOR_SHIFT : 0,
@@ -138,7 +152,7 @@ static int _text_write(struct label *label, void *buf)
 
        if (da1 < 0) {
                log_error(INTERNAL_ERROR "%s label header currently requires "
-                         "a data area.", dev_name(info->dev));
+                         "a data area.", dev_name(lvmcache_device(info)));
                return 0;
        }
 
@@ -250,6 +264,62 @@ static int _text_initialise_label(struct labeller *l __attribute__((unused)),
        return 1;
 }
 
+struct _update_mda_baton {
+       struct lvmcache_info *info;
+       struct label *label;
+};
+
+static int _update_mda(struct metadata_area *mda, void *baton)
+{
+       struct _update_mda_baton *p = baton;
+       const struct format_type *fmt = p->label->labeller->private; // Oh dear.
+       struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
+       struct mda_header *mdah;
+       const char *vgname = NULL;
+       struct id vgid;
+       uint64_t vgstatus;
+       char *creation_host;
+
+       if (!dev_open_readonly(mdac->area.dev)) {
+               mda_set_ignored(mda, 1);
+               stack;
+               return 1;
+       }
+
+       if (!(mdah = raw_read_mda_header(fmt, &mdac->area))) {
+               stack;
+               goto close_dev;
+       }
+
+       mda_set_ignored(mda, rlocn_is_ignored(mdah->raw_locns));
+
+       if (mda_is_ignored(mda)) {
+               log_debug("Ignoring mda on device %s at offset %"PRIu64,
+                         dev_name(mdac->area.dev),
+                         mdac->area.start);
+               if (!dev_close(mdac->area.dev))
+                       stack;
+               return 1;
+       }
+
+       if ((vgname = vgname_from_mda(fmt, mdah,
+                                     &mdac->area,
+                                     &vgid, &vgstatus, &creation_host,
+                                     &mdac->free_sectors)) &&
+           !lvmcache_update_vgname_and_id(p->info, vgname,
+                                          (char *) &vgid, vgstatus,
+                                          creation_host)) {
+               if (!dev_close(mdac->area.dev))
+                       stack;
+               return_0;
+       }
+close_dev:
+       if (!dev_close(mdac->area.dev))
+               stack;
+
+       return 1;
+}
+
 static int _text_read(struct labeller *l, struct device *dev, void *buf,
                 struct label **label)
 {
@@ -258,87 +328,41 @@ static int _text_read(struct labeller *l, struct device *dev, void *buf,
        struct lvmcache_info *info;
        struct disk_locn *dlocn_xl;
        uint64_t offset;
-       struct metadata_area *mda;
-       struct id vgid;
-       struct mda_context *mdac;
-       const char *vgname;
-       uint64_t vgstatus;
-       char *creation_host;
-       struct mda_header *mdah;
+       struct _update_mda_baton baton;
 
-       pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl));
+       pvhdr = (struct pv_header *) ((char *) buf + xlate32(lh->offset_xl));
 
        if (!(info = lvmcache_add(l, (char *)pvhdr->pv_uuid, dev,
                                  FMT_TEXT_ORPHAN_VG_NAME,
                                  FMT_TEXT_ORPHAN_VG_NAME, 0)))
                return_0;
-       *label = info->label;
 
-       info->device_size = xlate64(pvhdr->device_size_xl);
+       *label = lvmcache_get_label(info);
 
-       if (info->das.n)
-               del_das(&info->das);
-       dm_list_init(&info->das);
+       lvmcache_set_device_size(info, xlate64(pvhdr->device_size_xl));
 
-       if (info->mdas.n)
-               del_mdas(&info->mdas);
-       dm_list_init(&info->mdas);
+       lvmcache_del_das(info);
+       lvmcache_del_mdas(info);
 
        /* Data areas holding the PEs */
        dlocn_xl = pvhdr->disk_areas_xl;
        while ((offset = xlate64(dlocn_xl->offset))) {
-               add_da(NULL, &info->das, offset,
-                      xlate64(dlocn_xl->size));
+               lvmcache_add_da(info, offset, xlate64(dlocn_xl->size));
                dlocn_xl++;
        }
 
        /* Metadata area headers */
        dlocn_xl++;
        while ((offset = xlate64(dlocn_xl->offset))) {
-               add_mda(info->fmt, NULL, &info->mdas, dev, offset,
-                       xlate64(dlocn_xl->size), 0);
+               lvmcache_add_mda(info, dev, offset, xlate64(dlocn_xl->size), 0);
                dlocn_xl++;
        }
 
-       dm_list_iterate_items(mda, &info->mdas) {
-               mdac = (struct mda_context *) mda->metadata_locn;
-               if (!dev_open(mdac->area.dev)) {
-                       mda_set_ignored(mda, 1);
-                       stack;
-                       continue;
-               }
-               if (!(mdah = raw_read_mda_header(info->fmt, &mdac->area))) {
-                       stack;
-                       goto close_dev;
-               }
-               mda_set_ignored(mda, rlocn_is_ignored(mdah->raw_locns));
-
-               if (mda_is_ignored(mda)) {
-                       log_debug("Ignoring mda on device %s at offset %"PRIu64,
-                                 dev_name(mdac->area.dev),
-                                 mdac->area.start);
-                       if (!dev_close(mdac->area.dev))
-                               stack;
-                       continue;
-               }
-
-               if ((vgname = vgname_from_mda(info->fmt, mdah,
-                                             &mdac->area,
-                                             &vgid, &vgstatus, &creation_host,
-                                             &mdac->free_sectors)) &&
-                   !lvmcache_update_vgname_and_id(info, vgname,
-                                                  (char *) &vgid, vgstatus,
-                                                  creation_host)) {
-                       if (!dev_close(mdac->area.dev))
-                                       stack;
-                       return_0;
-               }
-       close_dev:
-               if (!dev_close(mdac->area.dev))
-                       stack;
-       }
+       baton.info = info;
+       baton.label = *label;
 
-       info->status &= ~CACHE_INVALID;
+       lvmcache_foreach_mda(info, _update_mda, &baton);
+       lvmcache_make_valid(info);
 
        return 1;
 }
@@ -348,10 +372,8 @@ static void _text_destroy_label(struct labeller *l __attribute__((unused)),
 {
        struct lvmcache_info *info = (struct lvmcache_info *) label->info;
 
-       if (info->mdas.n)
-               del_mdas(&info->mdas);
-       if (info->das.n)
-               del_das(&info->das);
+       lvmcache_del_mdas(info);
+       lvmcache_del_das(info);
 }
 
 static void _fmt_text_destroy(struct labeller *l)
index 8e73be0c6feb6fe862c0506ef5cda5c8984bd3d9..1dce24370e3399333f2822187be40f785147cb8a 100644 (file)
 #include "lib.h"
 #include "toolcontext.h"
 #include "segtype.h"
-#include "display.h"
-#include "text_export.h"
-#include "text_import.h"
-#include "config.h"
-#include "str_list.h"
-#include "targets.h"
-#include "lvm-string.h"
-#include "activate.h"
-#include "str_list.h"
-#include "metadata.h"
 
 static const char *_freeseg_name(const struct lv_segment *seg)
 {
@@ -43,7 +33,7 @@ static struct segtype_handler _freeseg_ops = {
 
 struct segment_type *init_free_segtype(struct cmd_context *cmd)
 {
-       struct segment_type *segtype = dm_malloc(sizeof(*segtype));
+       struct segment_type *segtype = dm_zalloc(sizeof(*segtype));
 
        if (!segtype)
                return_NULL;
index c622812ff4ca48c97f5a78a7567d06d3f17d0b74..b1124fc65fe50a1438f922437925b8458cb4335b 100644 (file)
@@ -18,6 +18,7 @@
 #include "crc.h"
 #include "xlate.h"
 #include "lvmcache.h"
+#include "lvmetad.h"
 #include "metadata.h"
 
 #include <sys/stat.h>
@@ -56,11 +57,6 @@ static struct labeller_i *_alloc_li(const char *name, struct labeller *l)
        return li;
 }
 
-static void _free_li(struct labeller_i *li)
-{
-       dm_free(li);
-}
-
 int label_init(void)
 {
        dm_list_init(&_labellers);
@@ -69,14 +65,12 @@ int label_init(void)
 
 void label_exit(void)
 {
-       struct dm_list *c, *n;
-       struct labeller_i *li;
+       struct labeller_i *li, *tli;
 
-       for (c = _labellers.n; c && c != &_labellers; c = n) {
-               n = c->n;
-               li = dm_list_item(c, struct labeller_i);
+       dm_list_iterate_items_safe(li, tli, &_labellers) {
+               dm_list_del(&li->list);
                li->l->ops->destroy(li->l);
-               _free_li(li);
+               dm_free(li);
        }
 
        dm_list_init(&_labellers);
@@ -156,8 +150,10 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
                dm_list_iterate_items(li, &_labellers) {
                        if (li->l->ops->can_handle(li->l, (char *) lh,
                                                   sector + scan_sector)) {
-                               log_very_verbose("%s: %s label detected",
-                                                dev_name(dev), li->name);
+                               log_very_verbose("%s: %s label detected at "
+                                                "sector %" PRIu64, 
+                                                dev_name(dev), li->name,
+                                                sector + scan_sector);
                                if (found) {
                                        log_error("Ignoring additional label "
                                                  "on %s at sector %" PRIu64,
@@ -177,9 +173,9 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
 
       out:
        if (!found) {
-               if ((info = info_from_pvid(dev->pvid, 0)))
-                       lvmcache_update_vgname_and_id(info, info->fmt->orphan_vg_name,
-                                                     info->fmt->orphan_vg_name,
+               if ((info = lvmcache_info_from_pvid(dev->pvid, 0)))
+                       lvmcache_update_vgname_and_id(info, lvmcache_fmt(info)->orphan_vg_name,
+                                                     lvmcache_fmt(info)->orphan_vg_name,
                                                      0, NULL);
                log_very_verbose("%s: No label detected", dev_name(dev));
        }
@@ -266,18 +262,18 @@ int label_read(struct device *dev, struct label **result,
        struct lvmcache_info *info;
        int r = 0;
 
-       if ((info = info_from_pvid(dev->pvid, 1))) {
+       if ((info = lvmcache_info_from_pvid(dev->pvid, 1))) {
                log_debug("Using cached label for %s", dev_name(dev));
-               *result = info->label;
+               *result = lvmcache_get_label(info);
                return 1;
        }
 
-       if (!dev_open(dev)) {
+       if (!dev_open_readonly(dev)) {
                stack;
 
-               if ((info = info_from_pvid(dev->pvid, 0)))
-                       lvmcache_update_vgname_and_id(info, info->fmt->orphan_vg_name,
-                                                     info->fmt->orphan_vg_name,
+               if ((info = lvmcache_info_from_pvid(dev->pvid, 0)))
+                       lvmcache_update_vgname_and_id(info, lvmcache_fmt(info)->orphan_vg_name,
+                                                     lvmcache_fmt(info)->orphan_vg_name,
                                                      0, NULL);
 
                return r;
@@ -352,10 +348,10 @@ int label_verify(struct device *dev)
        struct lvmcache_info *info;
        int r = 0;
 
-       if (!dev_open(dev)) {
-               if ((info = info_from_pvid(dev->pvid, 0)))
-                       lvmcache_update_vgname_and_id(info, info->fmt->orphan_vg_name,
-                                                     info->fmt->orphan_vg_name,
+       if (!dev_open_readonly(dev)) {
+               if ((info = lvmcache_info_from_pvid(dev->pvid, 0)))
+                       lvmcache_update_vgname_and_id(info, lvmcache_fmt(info)->orphan_vg_name,
+                                                     lvmcache_fmt(info)->orphan_vg_name,
                                                      0, NULL);
 
                return_0;
index 3e07f06df59d16fad690f308474fffe9ce50b612..f3268bbd375088debd354ac5db88a8a4dc71d50e 100644 (file)
@@ -26,6 +26,8 @@
 
 struct labeller;
 
+void allow_reads_with_lvmetad(void);
+
 /* On disk - 32 bytes */
 struct label_header {
        int8_t id[8];           /* LABELONE */
index eea9974a33b95bb89c5c2596bd06b4b17ba49c66..f9d63281c41864c6b2081e9e24965b485ce8ba67 100644 (file)
@@ -36,7 +36,7 @@
 int lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags);
 int query_resource(const char *resource, int *mode);
 void locking_end(void);
-int locking_init(int type, struct config_tree *cf, uint32_t *flags);
+int locking_init(int type, struct dm_config_tree *cf, uint32_t *flags);
 #endif
 
 typedef struct lvm_response {
@@ -62,28 +62,30 @@ static int _clvmd_sock = -1;
 /* FIXME Install SIGPIPE handler? */
 
 /* Open connection to the Cluster Manager daemon */
-static int _open_local_sock(void)
+static int _open_local_sock(int suppress_messages)
 {
        int local_socket;
-       struct sockaddr_un sockaddr;
+       struct sockaddr_un sockaddr = { .sun_family = AF_UNIX };
+
+       if (!dm_strncpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(sockaddr.sun_path))) {
+               log_error("%s: clvmd socket name too long.", CLVMD_SOCKNAME);
+               return -1;
+       }
 
        /* Open local socket */
        if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
-               log_error("Local socket creation failed: %s", strerror(errno));
+               log_error_suppress(suppress_messages, "Local socket "
+                                  "creation failed: %s", strerror(errno));
                return -1;
        }
 
-       memset(&sockaddr, 0, sizeof(sockaddr));
-       memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME));
-
-       sockaddr.sun_family = AF_UNIX;
 
        if (connect(local_socket,(struct sockaddr *) &sockaddr,
                    sizeof(sockaddr))) {
                int saved_errno = errno;
 
-               log_error("connect() failed on local socket: %s",
-                         strerror(errno));
+               log_error_suppress(suppress_messages, "connect() failed "
+                                  "on local socket: %s", strerror(errno));
                if (close(local_socket))
                        stack;
 
@@ -100,7 +102,7 @@ static int _send_request(char *inbuf, int inlen, char **retbuf)
        char outbuf[PIPE_BUF] __attribute__((aligned(8)));
        struct clvm_header *outheader = (struct clvm_header *) outbuf;
        int len;
-       int off;
+       unsigned off;
        int buflen;
        int err;
 
@@ -173,24 +175,23 @@ static void _build_header(struct clvm_header *head, int clvmd_cmd, const char *n
        head->cmd = clvmd_cmd;
        head->status = 0;
        head->flags = 0;
+       head->xid = 0;
        head->clientid = 0;
        head->arglen = len;
 
-       if (node) {
-               /*
-                * Allow a couple of special node names:
-                * "*" for all nodes,
-                * "." for the local node only
-                */
-               if (strcmp(node, "*") == 0) {
-                       head->node[0] = '\0';
-               } else if (strcmp(node, ".") == 0) {
-                       head->node[0] = '\0';
-                       head->flags = CLVMD_FLAG_LOCAL;
-               } else
-                       strcpy(head->node, node);
-       } else
+       /*
+        * Handle special node names.
+        */
+       if (!node || !strcmp(node, NODE_ALL))
+               head->node[0] = '\0';
+       else if (!strcmp(node, NODE_LOCAL)) {
+               head->node[0] = '\0';
+               head->flags = CLVMD_FLAG_LOCAL;
+       } else if (!strcmp(node, NODE_REMOTE)) {
                head->node[0] = '\0';
+               head->flags = CLVMD_FLAG_REMOTE;
+       } else
+               strcpy(head->node, node);
 }
 
 /*
@@ -211,16 +212,17 @@ static int _cluster_request(char clvmd_cmd, const char *node, void *data, int le
        *num = 0;
 
        if (_clvmd_sock == -1)
-               _clvmd_sock = _open_local_sock();
+               _clvmd_sock = _open_local_sock(0);
 
        if (_clvmd_sock == -1)
                return 0;
 
-       _build_header(head, clvmd_cmd, node, len);
+       /* 1 byte is used from struct clvm_header.args[1], so -> len - 1 */
+       _build_header(head, clvmd_cmd, node, len - 1);
        memcpy(head->node + strlen(head->node) + 1, data, len);
 
        status = _send_request(outbuf, sizeof(struct clvm_header) +
-                             strlen(head->node) + len, &retbuf);
+                             strlen(head->node) + len - 1, &retbuf);
        if (!status)
                goto out;
 
@@ -279,8 +281,7 @@ static int _cluster_request(char clvmd_cmd, const char *node, void *data, int le
        *response = rarray;
 
       out:
-       if (retbuf)
-               dm_free(retbuf);
+       dm_free(retbuf);
 
        return status;
 }
@@ -318,22 +319,33 @@ static int _lock_for_cluster(struct cmd_context *cmd, unsigned char clvmd_cmd,
        args = alloca(len);
        strcpy(args + 2, name);
 
-       /* Mask off lock flags */
-       args[0] = flags & (LCK_SCOPE_MASK | LCK_TYPE_MASK | LCK_NONBLOCK | LCK_HOLD); 
-       args[1] = flags & (LCK_LOCAL | LCK_CLUSTER_VG);
+       /* args[0] holds bottom 8 bits except LCK_LOCAL (0x40). */
+       args[0] = flags & (LCK_SCOPE_MASK | LCK_TYPE_MASK | LCK_NONBLOCK | LCK_HOLD | LCK_CLUSTER_VG); 
+
+       args[1] = 0;
 
        if (flags & LCK_ORIGIN_ONLY)
                args[1] |= LCK_ORIGIN_ONLY_MODE;
 
+       if (flags & LCK_REVERT)
+               args[1] |= LCK_REVERT_MODE;
+
        if (mirror_in_sync())
                args[1] |= LCK_MIRROR_NOSYNC_MODE;
 
+       if (test_mode())
+               args[1] |= LCK_TEST_MODE;
+
        /*
-        * Must handle tri-state return from dmeventd_monitor_mode.
-        * But DMEVENTD_MONITOR_IGNORE is not propagated across the cluster.
+        * We propagate dmeventd_monitor_mode() to clvmd faithfully, since
+        * dmeventd monitoring is tied to activation which happens inside clvmd
+        * when locking_type = 3.
         */
        dmeventd_mode = dmeventd_monitor_mode();
-       if (dmeventd_mode != DMEVENTD_MONITOR_IGNORE && dmeventd_mode)
+       if (dmeventd_mode == DMEVENTD_MONITOR_IGNORE)
+               args[1] |= LCK_DMEVENTD_MONITOR_IGNORE;
+
+       if (dmeventd_mode)
                args[1] |= LCK_DMEVENTD_MONITOR_MODE;
 
        if (cmd->partial_activation)
@@ -343,17 +355,24 @@ static int _lock_for_cluster(struct cmd_context *cmd, unsigned char clvmd_cmd,
         * VG locks are just that: locks, and have no side effects
         * so we only need to do them on the local node because all
         * locks are cluster-wide.
-        * Also, if the lock is exclusive it makes no sense to try to
-        * acquire it on all nodes, so just do that on the local node too.
-        * One exception, is that P_ locks /do/ get distributed across
-        * the cluster because they might have side-effects.
+        *
+        * P_ locks /do/ get distributed across the cluster because they might
+        * have side-effects.
+        *
+        * SYNC_NAMES and VG_BACKUP use the VG name directly without prefix.
         */
-       if (strncmp(name, "P_", 2) &&
-           (clvmd_cmd == CLVMD_CMD_LOCK_VG ||
-            (flags & LCK_TYPE_MASK) == LCK_EXCL ||
-            (flags & LCK_LOCAL) ||
-            !(flags & LCK_CLUSTER_VG)))
-               node = ".";
+       if (clvmd_cmd == CLVMD_CMD_SYNC_NAMES) {
+               if (flags & LCK_LOCAL)
+                       node = NODE_LOCAL;
+       } else if (clvmd_cmd != CLVMD_CMD_VG_BACKUP) {
+               if (strncmp(name, "P_", 2) &&
+                   (clvmd_cmd == CLVMD_CMD_LOCK_VG ||
+                    (flags & LCK_LOCAL) ||
+                    !(flags & LCK_CLUSTER_VG)))
+                       node = NODE_LOCAL;
+               else if (flags & LCK_REMOTE)
+                       node = NODE_REMOTE;
+       }
 
        status = _cluster_request(clvmd_cmd, node, args, len,
                                  &response, &num_responses);
@@ -401,6 +420,11 @@ int lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags)
 
        switch (flags & LCK_SCOPE_MASK) {
        case LCK_VG:
+               if (!strcmp(resource, VG_SYNC_NAMES)) {
+                       log_very_verbose("Requesting sync names.");
+                       return _lock_for_cluster(cmd, CLVMD_CMD_SYNC_NAMES,
+                                                flags & ~LCK_HOLD, resource);
+               }
                if (flags == LCK_VG_BACKUP) {
                        log_very_verbose("Requesting backup of VG metadata for %s",
                                         resource);
@@ -409,12 +433,14 @@ int lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags)
                }
 
                /* If the VG name is empty then lock the unused PVs */
-               if (is_orphan_vg(resource) || is_global_vg(resource) || (flags & LCK_CACHE))
-                       dm_snprintf(lockname, sizeof(lockname), "P_%s",
-                                   resource);
-               else
-                       dm_snprintf(lockname, sizeof(lockname), "V_%s",
-                                   resource);
+               if (dm_snprintf(lockname, sizeof(lockname), "%c_%s",
+                               (is_orphan_vg(resource) ||
+                                is_global_vg(resource) ||
+                                (flags & LCK_CACHE)) ?  'P' : 'V',
+                               resource)  < 0) {
+                       log_error("Locking resource %s too long.", resource);
+                       return 0;
+               }
 
                lock_scope = "VG";
                clvmd_cmd = CLVMD_CMD_LOCK_VG;
@@ -465,14 +491,16 @@ int lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags)
                return 0;
        }
 
-       log_very_verbose("Locking %s %s %s (%s%s%s%s%s%s%s) (0x%x)", lock_scope, lockname,
+       log_very_verbose("Locking %s %s %s (%s%s%s%s%s%s%s%s%s) (0x%x)", lock_scope, lockname,
                         lock_type, lock_scope,
                         flags & LCK_NONBLOCK ? "|NONBLOCK" : "",
                         flags & LCK_HOLD ? "|HOLD" : "",
-                        flags & LCK_LOCAL ? "|LOCAL" : "",
                         flags & LCK_CLUSTER_VG ? "|CLUSTER" : "",
+                        flags & LCK_LOCAL ? "|LOCAL" : "",
+                        flags & LCK_REMOTE ? "|REMOTE" : "",
                         flags & LCK_CACHE ? "|CACHE" : "",
                         flags & LCK_ORIGIN_ONLY ? "|ORIGIN_ONLY" : "",
+                        flags & LCK_REVERT ? "|REVERT" : "",
                         flags);
 
        /* Send a message to the cluster manager */
@@ -483,11 +511,11 @@ static int decode_lock_type(const char *response)
 {
        if (!response)
                return LCK_NULL;
-       else if (strcmp(response, "EX"))
+       else if (!strcmp(response, "EX"))
                return LCK_EXCL;
-       else if (strcmp(response, "CR"))
+       else if (!strcmp(response, "CR"))
                return LCK_READ;
-       else if (strcmp(response, "PR"))
+       else if (!strcmp(response, "PR"))
                return LCK_PREAD;
 
        stack;
@@ -511,7 +539,7 @@ int query_resource(const char *resource, int *mode)
        strcpy(args + 2, resource);
 
        args[0] = 0;
-       args[1] = LCK_CLUSTER_VG;
+       args[1] = 0;
 
        status = _cluster_request(CLVMD_CMD_LOCK_QUERY, node, args, len,
                                  &response, &num_responses);
@@ -525,8 +553,8 @@ int query_resource(const char *resource, int *mode)
 
                /*
                 * All nodes should use CR, or exactly one node
-                * should held EX. (PR is obsolete)
-                * If two nodes node reports different locks,
+                * should hold EX. (PR is obsolete)
+                * If two nodes report different locks,
                 * something is broken - just return more important mode.
                 */
                if (decode_lock_type(response[i].response) > *mode)
@@ -563,13 +591,14 @@ void reset_locking(void)
        if (close(_clvmd_sock))
                stack;
 
-       _clvmd_sock = _open_local_sock();
+       _clvmd_sock = _open_local_sock(0);
        if (_clvmd_sock == -1)
                stack;
 }
 
 #ifdef CLUSTER_LOCKING_INTERNAL
-int init_cluster_locking(struct locking_type *locking, struct cmd_context *cmd)
+int init_cluster_locking(struct locking_type *locking, struct cmd_context *cmd,
+                        int suppress_messages)
 {
        locking->lock_resource = _lock_resource;
        locking->query_resource = _query_resource;
@@ -577,16 +606,16 @@ int init_cluster_locking(struct locking_type *locking, struct cmd_context *cmd)
        locking->reset_locking = _reset_locking;
        locking->flags = LCK_PRE_MEMLOCK | LCK_CLUSTERED;
 
-       _clvmd_sock = _open_local_sock();
+       _clvmd_sock = _open_local_sock(suppress_messages);
        if (_clvmd_sock == -1)
                return 0;
 
        return 1;
 }
 #else
-int locking_init(int type, struct config_tree *cf, uint32_t *flags)
+int locking_init(int type, struct dm_config_tree *cf, uint32_t *flags)
 {
-       _clvmd_sock = _open_local_sock();
+       _clvmd_sock = _open_local_sock(0);
        if (_clvmd_sock == -1)
                return 0;
 
index 949d0650a2a3eeb439fca1ff0f1d037db77a8d94..4dacbe4d3e0cf9a41a34e4c8ce1d9466ee65e5f9 100644 (file)
 #include "defaults.h"
 #include "sharedlib.h"
 #include "toolcontext.h"
+#include "activate.h"
+#include "locking.h"
 
 static void *_locking_lib = NULL;
 static void (*_reset_fn) (void) = NULL;
 static void (*_end_fn) (void) = NULL;
 static int (*_lock_fn) (struct cmd_context * cmd, const char *resource,
                        uint32_t flags) = NULL;
-static int (*_init_fn) (int type, struct config_tree * cft,
+static int (*_init_fn) (int type, struct dm_config_tree * cft,
                        uint32_t *flags) = NULL;
 static int (*_lock_query_fn) (const char *resource, int *mode) = NULL;
 
 static int _lock_resource(struct cmd_context *cmd, const char *resource,
                          uint32_t flags)
 {
-       if (_lock_fn)
-               return _lock_fn(cmd, resource, flags);
-       else
+       if (!_lock_fn)
                return 0;
+
+       if (!strcmp(resource, VG_SYNC_NAMES)) {
+               /* Hide this lock request from external locking */
+               fs_unlock();
+               return 1;
+       }
+
+       return _lock_fn(cmd, resource, flags);
 }
 
 static void _fin_external_locking(void)
@@ -57,12 +65,13 @@ static void _reset_external_locking(void)
                _reset_fn();
 }
 
-int init_external_locking(struct locking_type *locking, struct cmd_context *cmd)
+int init_external_locking(struct locking_type *locking, struct cmd_context *cmd,
+                         int suppress_messages)
 {
        const char *libname;
 
        if (_locking_lib) {
-               log_error("External locking already initialised");
+               log_error_suppress(suppress_messages, "External locking already initialised");
                return 1;
        }
 
@@ -82,16 +91,16 @@ int init_external_locking(struct locking_type *locking, struct cmd_context *cmd)
            !(_lock_fn = dlsym(_locking_lib, "lock_resource")) ||
            !(_reset_fn = dlsym(_locking_lib, "reset_locking")) ||
            !(_end_fn = dlsym(_locking_lib, "locking_end"))) {
-               log_error("Shared library %s does not contain locking "
-                         "functions", libname);
+               log_error_suppress(suppress_messages, "Shared library %s does "
+                                  "not contain locking functions", libname);
                dlclose(_locking_lib);
                _locking_lib = NULL;
                return 0;
        }
 
        if (!(_lock_query_fn = dlsym(_locking_lib, "query_resource")))
-               log_warn("WARNING: %s: _query_resource() missing: "
-                        "Using inferior activation method.", libname);
+               log_warn_suppress(suppress_messages, "WARNING: %s: _query_resource() "
+                                 "missing: Using inferior activation method.", libname);
 
        log_verbose("Loaded external locking library %s", libname);
        return _init_fn(2, cmd->cft, &locking->flags);
index 9137a30a51306fa93bf079249d073c93d50abeeb..7755ae442c166ff6e52e031cc90f8860f183e156 100644 (file)
@@ -161,7 +161,8 @@ static int _do_flock(const char *file, int *fd, int operation, uint32_t nonblock
                if (r) {
                        errno = old_errno;
                        log_sys_error("flock", file);
-                       close(*fd);
+                       if (close(*fd))
+                               log_sys_error("close", file);
                        return 0;
                }
 
@@ -257,6 +258,7 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
 {
        char lockfile[PATH_MAX];
        unsigned origin_only = (flags & LCK_ORIGIN_ONLY) ? 1 : 0;
+       unsigned revert = (flags & LCK_REVERT) ? 1 : 0;
 
        switch (flags & LCK_SCOPE_MASK) {
        case LCK_VG:
@@ -264,16 +266,27 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
                if (strcmp(resource, VG_GLOBAL))
                        lvmcache_drop_metadata(resource, 0);
 
+               if (!strcmp(resource, VG_SYNC_NAMES))
+                       fs_unlock();
+
                /* LCK_CACHE does not require a real lock */
                if (flags & LCK_CACHE)
                        break;
 
-               if (is_orphan_vg(resource) || is_global_vg(resource))
-                       dm_snprintf(lockfile, sizeof(lockfile),
-                                    "%s/P_%s", _lock_dir, resource + 1);
-               else
-                       dm_snprintf(lockfile, sizeof(lockfile),
-                                    "%s/V_%s", _lock_dir, resource);
+               if (is_orphan_vg(resource) || is_global_vg(resource)) {
+                       if (dm_snprintf(lockfile, sizeof(lockfile),
+                                       "%s/P_%s", _lock_dir, resource + 1) < 0) {
+                               log_error("Too long locking filename %s/P_%s.",
+                                         _lock_dir, resource + 1);
+                               return 0;
+                       }
+               } else
+                       if (dm_snprintf(lockfile, sizeof(lockfile),
+                                       "%s/V_%s", _lock_dir, resource) < 0) {
+                               log_error("Too long locking filename %s/V_%s.",
+                                         _lock_dir, resource);
+                               return 0;
+                       }
 
                if (!_lock_file(lockfile, flags))
                        return_0;
@@ -281,8 +294,8 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
        case LCK_LV:
                switch (flags & LCK_TYPE_MASK) {
                case LCK_UNLOCK:
-                       log_very_verbose("Unlocking LV %s%s", resource, origin_only ? " without snapshots" : "");
-                       if (!lv_resume_if_active(cmd, resource, origin_only))
+                       log_very_verbose("Unlocking LV %s%s%s", resource, origin_only ? " without snapshots" : "", revert ? " (reverting)" : "");
+                       if (!lv_resume_if_active(cmd, resource, origin_only, 0, revert))
                                return 0;
                        break;
                case LCK_NULL:
@@ -300,7 +313,7 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
                        break;
                case LCK_WRITE:
                        log_very_verbose("Locking LV %s (W)%s", resource, origin_only ? " without snapshots" : "");
-                       if (!lv_suspend_if_active(cmd, resource, origin_only))
+                       if (!lv_suspend_if_active(cmd, resource, origin_only, 0))
                                return 0;
                        break;
                case LCK_EXCL:
@@ -321,18 +334,26 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
        return 1;
 }
 
-int init_file_locking(struct locking_type *locking, struct cmd_context *cmd)
+int init_file_locking(struct locking_type *locking, struct cmd_context *cmd,
+                     int suppress_messages)
 {
+       int r;
+       const char *locking_dir;
+
        locking->lock_resource = _file_lock_resource;
        locking->reset_locking = _reset_file_locking;
        locking->fin_locking = _fin_file_locking;
        locking->flags = 0;
-       int r;
 
        /* Get lockfile directory from config file */
-       strncpy(_lock_dir, find_config_tree_str(cmd, "global/locking_dir",
-                                               DEFAULT_LOCK_DIR),
-               sizeof(_lock_dir));
+       locking_dir = find_config_tree_str(cmd, "global/locking_dir",
+                                          DEFAULT_LOCK_DIR);
+       if (strlen(locking_dir) >= sizeof(_lock_dir)) {
+               log_error("Path for locking_dir %s is invalid.", locking_dir);
+               return 0;
+       }
+
+       strcpy(_lock_dir, locking_dir);
 
        _prioritise_write_locks =
            find_config_tree_bool(cmd, "global/prioritise_write_locks",
@@ -352,12 +373,14 @@ int init_file_locking(struct locking_type *locking, struct cmd_context *cmd)
        dm_list_init(&_lock_list);
 
        if (sigfillset(&_intsigset) || sigfillset(&_fullsigset)) {
-               log_sys_error("sigfillset", "init_file_locking");
+               log_sys_error_suppress(suppress_messages, "sigfillset",
+                                      "init_file_locking");
                return 0;
        }
 
        if (sigdelset(&_intsigset, SIGINT)) {
-               log_sys_error("sigdelset", "init_file_locking");
+               log_sys_error_suppress(suppress_messages, "sigdelset",
+                                      "init_file_locking");
                return 0;
        }
 
index 60eaab3ec53bde21d58e79c7e1aba6b92f0359d1..7aa519b62e725cacb4bd41182ba2f59522a449c2 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -167,7 +167,7 @@ static void _lock_memory(struct cmd_context *cmd, lv_operation_t lv_op)
                return;
 
        if (lv_op == LV_SUSPEND)
-               memlock_inc(cmd);
+               critical_section_inc(cmd, "locking for suspend");
 }
 
 static void _unlock_memory(struct cmd_context *cmd, lv_operation_t lv_op)
@@ -176,7 +176,7 @@ static void _unlock_memory(struct cmd_context *cmd, lv_operation_t lv_op)
                return;
 
        if (lv_op == LV_RESUME)
-               memlock_dec(cmd);
+               critical_section_dec(cmd, "unlocking on resume");
 }
 
 void reset_locking(void)
@@ -191,6 +191,8 @@ void reset_locking(void)
 
        if (was_locked)
                _unblock_signals();
+
+       memlock_reset();
 }
 
 static void _update_vg_lock_count(const char *resource, uint32_t flags)
@@ -219,7 +221,7 @@ static void _update_vg_lock_count(const char *resource, uint32_t flags)
  */
 int init_locking(int type, struct cmd_context *cmd, int suppress_messages)
 {
-       if (ignorelockingfailure() && getenv("LVM_SUPPRESS_LOCKING_FAILURE_MESSAGES"))
+       if (getenv("LVM_SUPPRESS_LOCKING_FAILURE_MESSAGES"))
                suppress_messages = 1;
 
        if (type < 0)
@@ -230,7 +232,7 @@ int init_locking(int type, struct cmd_context *cmd, int suppress_messages)
 
        switch (type) {
        case 0:
-               init_no_locking(&_locking, cmd);
+               init_no_locking(&_locking, cmd, suppress_messages);
                log_warn("WARNING: Locking disabled. Be careful! "
                          "This could corrupt your metadata.");
                return 1;
@@ -239,7 +241,7 @@ int init_locking(int type, struct cmd_context *cmd, int suppress_messages)
                log_very_verbose("%sFile-based locking selected.",
                                 _blocking_supported ? "" : "Non-blocking ");
 
-               if (!init_file_locking(&_locking, cmd)) {
+               if (!init_file_locking(&_locking, cmd, suppress_messages)) {
                        log_error_suppress(suppress_messages,
                                           "File-based locking initialisation failed.");
                        break;
@@ -250,13 +252,13 @@ int init_locking(int type, struct cmd_context *cmd, int suppress_messages)
        case 2:
                if (!is_static()) {
                        log_very_verbose("External locking selected.");
-                       if (init_external_locking(&_locking, cmd))
+                       if (init_external_locking(&_locking, cmd, suppress_messages))
                                return 1;
                }
                if (!find_config_tree_int(cmd, "locking/fallback_to_clustered_locking",
                            find_config_tree_int(cmd, "global/fallback_to_clustered_locking",
                                                 DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING))) {
-                       log_error("External locking initialisation failed.");
+                       log_error_suppress(suppress_messages, "External locking initialisation failed.");
                        break;
                }
 #endif
@@ -267,7 +269,7 @@ int init_locking(int type, struct cmd_context *cmd, int suppress_messages)
 
        case 3:
                log_very_verbose("Cluster locking selected.");
-               if (!init_cluster_locking(&_locking, cmd)) {
+               if (!init_cluster_locking(&_locking, cmd, suppress_messages)) {
                        log_error_suppress(suppress_messages,
                                           "Internal cluster locking initialisation failed.");
                        break;
@@ -278,7 +280,7 @@ int init_locking(int type, struct cmd_context *cmd, int suppress_messages)
        case 4:
                log_verbose("Read-only locking selected. "
                            "Only read operations permitted.");
-               if (!init_readonly_locking(&_locking, cmd))
+               if (!init_readonly_locking(&_locking, cmd, suppress_messages))
                        break;
                return 1;
 
@@ -295,7 +297,7 @@ int init_locking(int type, struct cmd_context *cmd, int suppress_messages)
                log_warn_suppress(suppress_messages,
                                  "Volume Groups with the clustered attribute will "
                                  "be inaccessible.");
-               if (init_file_locking(&_locking, cmd))
+               if (init_file_locking(&_locking, cmd, suppress_messages))
                        return 1;
                else
                        log_error_suppress(suppress_messages,
@@ -306,7 +308,7 @@ int init_locking(int type, struct cmd_context *cmd, int suppress_messages)
                return 0;
 
        log_verbose("Locking disabled - only read operations permitted.");
-       init_readonly_locking(&_locking, cmd);
+       init_readonly_locking(&_locking, cmd, suppress_messages);
 
        return 1;
 }
@@ -325,7 +327,7 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname)
        char path[PATH_MAX];
 
        /* We'll allow operations on orphans */
-       if (is_orphan_vg(vgname) || is_global_vg(vgname))
+       if (!is_real_vg(vgname))
                return 1;
 
        /* LVM1 is only present in 2.4 kernels. */
@@ -357,6 +359,8 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname)
 static int _lock_vol(struct cmd_context *cmd, const char *resource,
                     uint32_t flags, lv_operation_t lv_op)
 {
+       uint32_t lck_type = flags & LCK_TYPE_MASK;
+       uint32_t lck_scope = flags & LCK_SCOPE_MASK;
        int ret = 0;
 
        _block_signals(flags);
@@ -374,21 +378,16 @@ static int _lock_vol(struct cmd_context *cmd, const char *resource,
                return 0;
        }
 
-       if (cmd->metadata_read_only &&
-           ((flags & LCK_TYPE_MASK) == LCK_WRITE) &&
+       if (cmd->metadata_read_only && lck_type == LCK_WRITE &&
            strcmp(resource, VG_GLOBAL)) {
                log_error("Operation prohibited while global/metadata_read_only is set.");
                return 0;
        }
 
        if ((ret = _locking.lock_resource(cmd, resource, flags))) {
-               if ((flags & LCK_SCOPE_MASK) == LCK_VG &&
-                   !(flags & LCK_CACHE)) {
-                       if ((flags & LCK_TYPE_MASK) == LCK_UNLOCK)
-                               lvmcache_unlock_vgname(resource);
-                       else
-                               lvmcache_lock_vgname(resource, (flags & LCK_TYPE_MASK)
-                                                               == LCK_READ);
+               if (lck_scope == LCK_VG && !(flags & LCK_CACHE)) {
+                       if (lck_type != LCK_UNLOCK)
+                               lvmcache_lock_vgname(resource, lck_type == LCK_READ);
                        dev_reset_error_count(cmd);
                }
 
@@ -396,6 +395,13 @@ static int _lock_vol(struct cmd_context *cmd, const char *resource,
        } else
                stack;
 
+       /* If unlocking, always remove lock from lvmcache even if operation failed. */
+       if (lck_scope == LCK_VG && !(flags & LCK_CACHE) && lck_type == LCK_UNLOCK) {
+               lvmcache_unlock_vgname(resource);
+               if (!ret)
+                       _update_vg_lock_count(resource, flags);
+       }
+
        _unlock_memory(cmd, lv_op);
        _unblock_signals();
 
@@ -406,6 +412,7 @@ int lock_vol(struct cmd_context *cmd, const char *vol, uint32_t flags)
 {
        char resource[258] __attribute__((aligned(8)));
        lv_operation_t lv_op;
+       int lck_type = flags & LCK_TYPE_MASK;
 
        switch (flags & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) {
                case LCK_LV_SUSPEND:
@@ -432,15 +439,15 @@ int lock_vol(struct cmd_context *cmd, const char *vol, uint32_t flags)
                if (is_orphan_vg(vol))
                        vol = VG_ORPHANS;
                /* VG locks alphabetical, ORPHAN lock last */
-               if (((flags & LCK_TYPE_MASK) != LCK_UNLOCK) &&
-                        !(flags & LCK_CACHE) &&
-                        !lvmcache_verify_lock_order(vol))
-                       return 0;
+               if ((lck_type != LCK_UNLOCK) &&
+                   !(flags & LCK_CACHE) &&
+                   !lvmcache_verify_lock_order(vol))
+                       return_0;
 
                /* Lock VG to change on-disk metadata. */
                /* If LVM1 driver knows about the VG, it can't be accessed. */
                if (!check_lvm1_vg_inactive(cmd, vol))
-                       return 0;
+                       return_0;
                break;
        case LCK_LV:
                /* All LV locks are non-blocking. */
@@ -452,21 +459,22 @@ int lock_vol(struct cmd_context *cmd, const char *vol, uint32_t flags)
                return 0;
        }
 
-       strncpy(resource, vol, sizeof(resource));
+       strncpy(resource, vol, sizeof(resource) - 1);
+       resource[sizeof(resource) - 1] = '\0';
 
        if (!_lock_vol(cmd, resource, flags, lv_op))
-               return 0;
+               return_0;
 
        /*
         * If a real lock was acquired (i.e. not LCK_CACHE),
         * perform an immediate unlock unless LCK_HOLD was requested.
         */
-       if (!(flags & LCK_CACHE) && !(flags & LCK_HOLD) &&
-           ((flags & LCK_TYPE_MASK) != LCK_UNLOCK)) {
-               if (!_lock_vol(cmd, resource,
-                              (flags & ~LCK_TYPE_MASK) | LCK_UNLOCK, lv_op))
-                       return 0;
-       }
+       if ((lck_type == LCK_NULL) || (lck_type == LCK_UNLOCK) ||
+           (flags & (LCK_CACHE | LCK_HOLD)))
+               return 1;
+
+       if (!_lock_vol(cmd, resource, (flags & ~LCK_TYPE_MASK) | LCK_UNLOCK, lv_op))
+               return_0;
 
        return 1;
 }
@@ -486,20 +494,44 @@ int resume_lvs(struct cmd_context *cmd, struct dm_list *lvs)
        return r;
 }
 
-/* Lock a list of LVs */
-int suspend_lvs(struct cmd_context *cmd, struct dm_list *lvs)
+/* Unlock and revert list of LVs */
+int revert_lvs(struct cmd_context *cmd, struct dm_list *lvs)
+{
+       struct lv_list *lvl;
+       int r = 1;
+
+       dm_list_iterate_items(lvl, lvs)
+               if (!revert_lv(cmd, lvl->lv)) {
+                       r = 0;
+                       stack;
+               }
+
+       return r;
+}
+/*
+ * Lock a list of LVs.
+ * On failure to lock any LV, calls vg_revert() if vg_to_revert is set and 
+ * then unlocks any LVs on the list already successfully locked.
+ */
+int suspend_lvs(struct cmd_context *cmd, struct dm_list *lvs,
+               struct volume_group *vg_to_revert)
 {
-       struct dm_list *lvh;
        struct lv_list *lvl;
 
        dm_list_iterate_items(lvl, lvs) {
                if (!suspend_lv(cmd, lvl->lv)) {
                        log_error("Failed to suspend %s", lvl->lv->name);
-                       dm_list_uniterate(lvh, lvs, &lvl->list) {
-                               lvl = dm_list_item(lvh, struct lv_list);
-                               if (!resume_lv(cmd, lvl->lv))
+                       if (vg_to_revert)
+                               vg_revert(vg_to_revert);
+                       /*
+                        * FIXME Should be
+                        *      dm_list_uniterate(lvh, lvs, &lvl->list) {
+                        *      lvl = dm_list_item(lvh, struct lv_list);
+                        * but revert would need fixing to use identical tree deps first.
+                        */
+                       dm_list_iterate_items(lvl, lvs)
+                               if (!revert_lv(cmd, lvl->lv))
                                        stack;
-                       }
 
                        return 0;
                }
@@ -508,6 +540,33 @@ int suspend_lvs(struct cmd_context *cmd, struct dm_list *lvs)
        return 1;
 }
 
+/*
+ * First try to activate exclusively locally.
+ * Then if the VG is clustered and the LV is not yet active (e.g. due to 
+ * an activation filter) try activating on remote nodes.
+ */
+int activate_lv_excl(struct cmd_context *cmd, struct logical_volume *lv) 
+{
+       /* Non-clustered VGs are only activated locally. */
+       if (!vg_is_clustered(lv->vg))
+               return activate_lv_excl_local(cmd, lv);
+
+       if (lv_is_active_exclusive_locally(lv))
+               return 1;
+
+       if (!activate_lv_excl_local(cmd, lv))
+               return_0;
+
+       if (lv_is_active_exclusive(lv))
+               return 1;
+
+       /* FIXME Deal with error return codes. */
+       if (activate_lv_excl_remote(cmd, lv))
+               stack;
+
+       return lv_is_active_exclusive(lv);
+}
+
 /* Lock a list of LVs */
 int activate_lvs(struct cmd_context *cmd, struct dm_list *lvs, unsigned exclusive)
 {
@@ -515,7 +574,7 @@ int activate_lvs(struct cmd_context *cmd, struct dm_list *lvs, unsigned exclusiv
        struct lv_list *lvl;
 
        dm_list_iterate_items(lvl, lvs) {
-               if (!exclusive) {
+               if (!exclusive && !lv_is_active_exclusive(lvl->lv)) {
                        if (!activate_lv(cmd, lvl->lv)) {
                                log_error("Failed to activate %s", lvl->lv->name);
                                return 0;
@@ -544,7 +603,7 @@ int locking_is_clustered(void)
        return (_locking.flags & LCK_CLUSTERED) ? 1 : 0;
 }
 
-int remote_lock_held(const char *vol)
+int remote_lock_held(const char *vol, int *exclusive)
 {
        int mode = LCK_NULL;
 
@@ -562,5 +621,22 @@ int remote_lock_held(const char *vol)
                return 1;
        }
 
+       if (exclusive)
+               *exclusive = (mode == LCK_EXCL);
+
        return mode == LCK_NULL ? 0 : 1;
 }
+
+int sync_local_dev_names(struct cmd_context* cmd)
+{
+       memlock_unlock(cmd);
+
+       return lock_vol(cmd, VG_SYNC_NAMES, LCK_VG_SYNC_LOCAL);
+}
+
+int sync_dev_names(struct cmd_context* cmd)
+{
+       memlock_unlock(cmd);
+
+       return lock_vol(cmd, VG_SYNC_NAMES, LCK_VG_SYNC);
+}
index 88935004f7472f72fdc28cd997285c896c501ca8..23c312d8e7040f921137743275284d47b98132a7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.  
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -25,7 +25,7 @@ void reset_locking(void);
 int vg_write_lock_held(void);
 int locking_is_clustered(void);
 
-int remote_lock_held(const char *vol);
+int remote_lock_held(const char *vol, int *exclusive);
 
 /*
  * LCK_VG:
@@ -39,6 +39,9 @@ int remote_lock_held(const char *vol);
  *   acquired in alphabetical order of 'vol' (to avoid deadlocks), with
  *   VG_ORPHANS last.
  *
+ *   Use VG_SYNC_NAMES to ensure /dev is up-to-date for example, with udev,
+ *   by waiting for any asynchronous events issued to have completed.
+ *
  * LCK_LV:
  *   Lock/unlock an individual logical volume
  *   char *vol holds lvid
@@ -64,13 +67,13 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
  */
 #define LCK_TYPE_MASK  0x00000007U
 
-#define LCK_NULL       0x00000000U     /* LCK$_NLMODE */
-#define LCK_READ       0x00000001U     /* LCK$_CRMODE */
+#define LCK_NULL       0x00000000U     /* LCK$_NLMODE (Deactivate) */
+#define LCK_READ       0x00000001U     /* LCK$_CRMODE (Activate) */
                                        /* LCK$_CWMODE */
 #define LCK_PREAD       0x00000003U    /* LCK$_PRMODE */
-#define LCK_WRITE      0x00000004U     /* LCK$_PWMODE */
-#define LCK_EXCL       0x00000005U     /* LCK$_EXMODE */
-#define LCK_UNLOCK      0x00000006U    /* This is ours */
+#define LCK_WRITE      0x00000004U     /* LCK$_PWMODE (Suspend) */
+#define LCK_EXCL       0x00000005U     /* LCK$_EXMODE (Exclusive) */
+#define LCK_UNLOCK      0x00000006U    /* This is ours (Resume) */
 
 /*
  * Lock flags - these numbers are the same as DLM
@@ -86,14 +89,18 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
 #define LCK_LV         0x00000008U
 
 /*
- * Lock bits
+ * Lock bits.
+ * Bottom 8 bits except LCK_LOCAL form args[0] in cluster comms.
  */
 #define LCK_NONBLOCK   0x00000010U     /* Don't block waiting for lock? */
 #define LCK_HOLD       0x00000020U     /* Hold lock when lock_vol returns? */
-#define LCK_LOCAL      0x00000040U     /* Don't propagate to other nodes */
 #define LCK_CLUSTER_VG 0x00000080U     /* VG is clustered */
+
+#define LCK_LOCAL      0x00000040U     /* Don't propagate to other nodes */
+#define LCK_REMOTE     0x00000800U     /* Propagate to remote nodes only */
 #define LCK_CACHE      0x00000100U     /* Operation on cache only using P_ lock */
 #define LCK_ORIGIN_ONLY        0x00000200U     /* Operation should bypass any snapshots */
+#define LCK_REVERT     0x00000400U     /* Revert any incomplete change */
 
 /*
  * Additional lock bits for cluster communication via args[1]
@@ -101,14 +108,21 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
 #define LCK_PARTIAL_MODE               0x01    /* Partial activation? */
 #define LCK_MIRROR_NOSYNC_MODE         0x02    /* Mirrors don't require sync */
 #define LCK_DMEVENTD_MONITOR_MODE      0x04    /* Register with dmeventd */
+
+/* Not yet used. */
 #define LCK_CONVERT                    0x08    /* Convert existing lock */
+
+#define LCK_TEST_MODE                  0x10    /* Test mode: No activation */
 #define LCK_ORIGIN_ONLY_MODE           0x20    /* Same as above */
+#define LCK_DMEVENTD_MONITOR_IGNORE     0x40   /* Whether to ignore dmeventd */
+#define LCK_REVERT_MODE                        0x80    /* Remove inactive tables */
 
 /*
  * Special cases of VG locks.
  */
 #define VG_ORPHANS     "#orphans"
 #define VG_GLOBAL      "#global"
+#define VG_SYNC_NAMES  "#sync_names"
 
 /*
  * Common combinations
@@ -126,6 +140,9 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
 
 #define LCK_VG_BACKUP          (LCK_VG | LCK_CACHE)
 
+#define LCK_VG_SYNC            (LCK_NONE | LCK_CACHE)
+#define LCK_VG_SYNC_LOCAL      (LCK_NONE | LCK_CACHE | LCK_LOCAL)
+
 #define LCK_LV_EXCLUSIVE       (LCK_LV | LCK_EXCL)
 #define LCK_LV_SUSPEND         (LCK_LV | LCK_WRITE)
 #define LCK_LV_RESUME          (LCK_LV | LCK_UNLOCK)
@@ -142,21 +159,34 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
                lock_vol(cmd, (lv)->lvid.s, flags | LCK_LV_CLUSTERED(lv)) : \
                0)
 
-#define unlock_vg(cmd, vol)    lock_vol(cmd, vol, LCK_VG_UNLOCK)
-#define unlock_and_free_vg(cmd, vg, vol) \
+#define unlock_vg(cmd, vol)    \
+       do { \
+               if (is_real_vg(vol)) \
+                       sync_dev_names(cmd); \
+               (void) lock_vol(cmd, vol, LCK_VG_UNLOCK); \
+       } while (0)
+#define unlock_and_release_vg(cmd, vg, vol) \
        do { \
                unlock_vg(cmd, vol); \
-               free_vg(vg); \
+               release_vg(vg); \
        } while (0)
 
 #define resume_lv(cmd, lv)     lock_lv_vol(cmd, lv, LCK_LV_RESUME)
 #define resume_lv_origin(cmd, lv)      lock_lv_vol(cmd, lv, LCK_LV_RESUME | LCK_ORIGIN_ONLY)
+#define revert_lv(cmd, lv)     lock_lv_vol(cmd, lv, LCK_LV_RESUME | LCK_REVERT)
 #define suspend_lv(cmd, lv)    lock_lv_vol(cmd, lv, LCK_LV_SUSPEND | LCK_HOLD)
 #define suspend_lv_origin(cmd, lv)     lock_lv_vol(cmd, lv, LCK_LV_SUSPEND | LCK_HOLD | LCK_ORIGIN_ONLY)
 #define deactivate_lv(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_DEACTIVATE)
+
 #define activate_lv(cmd, lv)   lock_lv_vol(cmd, lv, LCK_LV_ACTIVATE | LCK_HOLD)
-#define activate_lv_excl(cmd, lv)      \
-                               lock_lv_vol(cmd, lv, LCK_LV_EXCLUSIVE | LCK_HOLD)
+#define activate_lv_excl_local(cmd, lv)        \
+                               lock_lv_vol(cmd, lv, LCK_LV_EXCLUSIVE | LCK_HOLD | LCK_LOCAL)
+#define activate_lv_excl_remote(cmd, lv)       \
+                               lock_lv_vol(cmd, lv, LCK_LV_EXCLUSIVE | LCK_HOLD | LCK_REMOTE)
+
+struct logical_volume;
+int activate_lv_excl(struct cmd_context *cmd, struct logical_volume *lv);
+
 #define activate_lv_local(cmd, lv)     \
        lock_lv_vol(cmd, lv, LCK_LV_ACTIVATE | LCK_HOLD | LCK_LOCAL)
 #define deactivate_lv_local(cmd, lv)   \
@@ -170,9 +200,15 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
 #define remote_backup_metadata(vg)     \
        lock_vol((vg)->cmd, (vg)->name, LCK_VG_BACKUP)
 
+int sync_local_dev_names(struct cmd_context* cmd);
+int sync_dev_names(struct cmd_context* cmd);
+
 /* Process list of LVs */
-int suspend_lvs(struct cmd_context *cmd, struct dm_list *lvs);
+struct volume_group;
+int suspend_lvs(struct cmd_context *cmd, struct dm_list *lvs,
+               struct volume_group *vg_to_revert);
 int resume_lvs(struct cmd_context *cmd, struct dm_list *lvs);
+int revert_lvs(struct cmd_context *cmd, struct dm_list *lvs);
 int activate_lvs(struct cmd_context *cmd, struct dm_list *lvs, unsigned exclusive);
 
 /* Interrupt handling */
index c3ca16b5e6a20968b79e4d0bbc931ae5c936fdff..53c7016e0df0f290f9568fcf8a769eda6ad84c23 100644 (file)
@@ -38,12 +38,17 @@ struct locking_type {
 /*
  * Locking types
  */
-int init_no_locking(struct locking_type *locking, struct cmd_context *cmd);
+int init_no_locking(struct locking_type *locking, struct cmd_context *cmd,
+                   int suppress_messages);
 
-int init_readonly_locking(struct locking_type *locking, struct cmd_context *cmd);
+int init_readonly_locking(struct locking_type *locking, struct cmd_context *cmd,
+                         int suppress_messages);
 
-int init_file_locking(struct locking_type *locking, struct cmd_context *cmd);
+int init_file_locking(struct locking_type *locking, struct cmd_context *cmd,
+                     int suppress_messages);
 
-int init_external_locking(struct locking_type *locking, struct cmd_context *cmd);
+int init_external_locking(struct locking_type *locking, struct cmd_context *cmd,
+                         int suppress_messages);
 
-int init_cluster_locking(struct locking_type *locking, struct cmd_context *cmd);
+int init_cluster_locking(struct locking_type *locking, struct cmd_context *cmd,
+                        int suppress_messages);
index 8c4110f543abe68e192d7d514eb945b184b6a999..53a59480f87efd7a21be01f77b64e5684e10de6f 100644 (file)
@@ -38,17 +38,19 @@ static int _no_lock_resource(struct cmd_context *cmd, const char *resource,
 {
        switch (flags & LCK_SCOPE_MASK) {
        case LCK_VG:
+               if (!strcmp(resource, VG_SYNC_NAMES))
+                       fs_unlock();
                break;
        case LCK_LV:
                switch (flags & LCK_TYPE_MASK) {
                case LCK_NULL:
                        return lv_deactivate(cmd, resource);
                case LCK_UNLOCK:
-                       return lv_resume_if_active(cmd, resource, (flags & LCK_ORIGIN_ONLY) ? 1: 0);
+                       return lv_resume_if_active(cmd, resource, (flags & LCK_ORIGIN_ONLY) ? 1: 0, 0, (flags & LCK_REVERT) ? 1 : 0);
                case LCK_READ:
                        return lv_activate_with_filter(cmd, resource, 0);
                case LCK_WRITE:
-                       return lv_suspend_if_active(cmd, resource, (flags & LCK_ORIGIN_ONLY) ? 1 : 0);
+                       return lv_suspend_if_active(cmd, resource, (flags & LCK_ORIGIN_ONLY) ? 1 : 0, 0);
                case LCK_EXCL:
                        return lv_activate_with_filter(cmd, resource, 1);
                default:
@@ -72,14 +74,16 @@ static int _readonly_lock_resource(struct cmd_context *cmd,
            (flags & LCK_SCOPE_MASK) == LCK_VG &&
            !(flags & LCK_CACHE) &&
            strcmp(resource, VG_GLOBAL)) {
-               log_error("Write locks are prohibited with read-only locking.");
+               log_error("Read-only locking type set. "
+                         "Write locks are prohibited.");
                return 0;
        }
 
        return _no_lock_resource(cmd, resource, flags);
 }
 
-int init_no_locking(struct locking_type *locking, struct cmd_context *cmd __attribute__((unused)))
+int init_no_locking(struct locking_type *locking, struct cmd_context *cmd __attribute__((unused)),
+                   int suppress_messages)
 {
        locking->lock_resource = _no_lock_resource;
        locking->reset_locking = _no_reset_locking;
@@ -89,7 +93,8 @@ int init_no_locking(struct locking_type *locking, struct cmd_context *cmd __attr
        return 1;
 }
 
-int init_readonly_locking(struct locking_type *locking, struct cmd_context *cmd __attribute__((unused)))
+int init_readonly_locking(struct locking_type *locking, struct cmd_context *cmd __attribute__((unused)),
+                         int suppress_messages)
 {
        locking->lock_resource = _readonly_lock_resource;
        locking->reset_locking = _no_reset_locking;
index 86b4988d2cb7b4a82931c5dab8c882e25d5dd406..d50cb4a42a199f26ffa1ed813401676e429c44d0 100644 (file)
 #include "lib.h"
 #include "device.h"
 #include "memlock.h"
-#include "lvm-string.h"
-#include "lvm-file.h"
 #include "defaults.h"
-#include "config.h"
 
 #include <stdarg.h>
 #include <syslog.h>
@@ -43,6 +40,9 @@ static lvm2_log_fn_t _lvm2_log_fn = NULL;
 static int _lvm_errno = 0;
 static int _store_errmsg = 0;
 static char *_lvm_errmsg = NULL;
+static size_t _lvm_errmsg_size = 0;
+static size_t _lvm_errmsg_len = 0;
+#define MAX_ERRMSG_LEN (512 * 1024)  /* Max size of error buffer 512KB */
 
 void init_log_fn(lvm2_log_fn_t log_fn)
 {
@@ -107,7 +107,7 @@ void release_log_memory(void)
 void fin_log(void)
 {
        if (_log_direct) {
-               dev_close(&_log_dev);
+               (void) dev_close(&_log_dev);
                _log_direct = 0;
        }
 
@@ -124,7 +124,7 @@ void fin_log(void)
        }
 }
 
-void fin_syslog()
+void fin_syslog(void)
 {
        if (_syslog)
                closelog();
@@ -133,7 +133,7 @@ void fin_syslog()
 
 void init_msg_prefix(const char *prefix)
 {
-       strncpy(_msg_prefix, prefix, sizeof(_msg_prefix));
+       strncpy(_msg_prefix, prefix, sizeof(_msg_prefix) - 1);
        _msg_prefix[sizeof(_msg_prefix) - 1] = '\0';
 }
 
@@ -154,6 +154,7 @@ void reset_lvm_errno(int store_errmsg)
        if (_lvm_errmsg) {
                dm_free(_lvm_errmsg);
                _lvm_errmsg = NULL;
+               _lvm_errmsg_size = _lvm_errmsg_len = 0;
        }
 
        _store_errmsg = store_errmsg;
@@ -172,16 +173,17 @@ const char *stored_errmsg(void)
 static struct dm_hash_table *_duplicated = NULL;
 
 void reset_log_duplicated(void) {
-       if (_duplicated)
+       if (_duplicated) {
                dm_hash_destroy(_duplicated);
-       _duplicated = NULL;
+               _duplicated = NULL;
+       }
 }
 
 void print_log(int level, const char *file, int line, int dm_errno,
               const char *format, ...)
 {
        va_list ap;
-       char buf[1024], buf2[4096], locn[4096];
+       char buf[1024], locn[4096];
        int bufused, n;
        const char *message;
        const char *trformat;           /* Translated format string */
@@ -189,6 +191,7 @@ void print_log(int level, const char *file, int line, int dm_errno,
        int use_stderr = level & _LOG_STDERR;
        int log_once = level & _LOG_ONCE;
        int fatal_internal_error = 0;
+       size_t msglen;
 
        level &= ~(_LOG_STDERR|_LOG_ONCE);
 
@@ -216,7 +219,7 @@ void print_log(int level, const char *file, int line, int dm_errno,
            (_store_errmsg && (level <= _LOG_ERR)) ||
            log_once) {
                va_start(ap, format);
-               n = vsnprintf(buf2, sizeof(buf2) - 1, trformat, ap);
+               n = vsnprintf(locn, sizeof(locn) - 1, trformat, ap);
                va_end(ap);
 
                if (n < 0) {
@@ -225,18 +228,29 @@ void print_log(int level, const char *file, int line, int dm_errno,
                        goto log_it;
                }
 
-               buf2[sizeof(buf2) - 1] = '\0';
-               message = &buf2[0];
+               locn[sizeof(locn) - 1] = '\0';
+               message = locn;
        }
 
-       if (_store_errmsg && (level <= _LOG_ERR)) {
-               if (!_lvm_errmsg)
-                       _lvm_errmsg = dm_strdup(message);
-               else if ((newbuf = dm_realloc(_lvm_errmsg,
-                                             strlen(_lvm_errmsg) +
-                                             strlen(message) + 2))) {
-                       _lvm_errmsg = strcat(newbuf, "\n");
-                       _lvm_errmsg = strcat(newbuf, message);
+/* FIXME Avoid pointless use of message buffer when it'll never be read! */
+       if (_store_errmsg && (level <= _LOG_ERR) &&
+           _lvm_errmsg_len < MAX_ERRMSG_LEN) {
+               msglen = strlen(message);
+               if ((_lvm_errmsg_len + msglen + 1) >= _lvm_errmsg_size) {
+                       _lvm_errmsg_size = 2 * (_lvm_errmsg_len + msglen + 1);
+                       if ((newbuf = dm_realloc(_lvm_errmsg,
+                                                _lvm_errmsg_size)))
+                               _lvm_errmsg = newbuf;
+                       else
+                               _lvm_errmsg_size = _lvm_errmsg_len;
+               }
+               if (_lvm_errmsg &&
+                   (_lvm_errmsg_len + msglen + 2) < _lvm_errmsg_size) {
+                       /* prepend '\n' and copy with '\0' but do not count in */
+                        if (_lvm_errmsg_len)
+                               _lvm_errmsg[_lvm_errmsg_len++] = '\n';
+                       memcpy(_lvm_errmsg + _lvm_errmsg_len, message, msglen + 1);
+                       _lvm_errmsg_len += msglen;
                }
        }
 
@@ -246,7 +260,7 @@ void print_log(int level, const char *file, int line, int dm_errno,
                if (_duplicated) {
                        if (dm_hash_lookup(_duplicated, message))
                                level = _LOG_NOTICE;
-                       dm_hash_insert(_duplicated, message, (void*)1);
+                       (void) dm_hash_insert(_duplicated, message, (void*)1);
                }
        }
 
@@ -260,8 +274,8 @@ void print_log(int level, const char *file, int line, int dm_errno,
       log_it:
        if (!_log_suppress) {
                if (verbose_level() > _LOG_DEBUG)
-                       dm_snprintf(locn, sizeof(locn), "#%s:%d ",
-                                    file, line);
+                       (void) dm_snprintf(locn, sizeof(locn), "#%s:%d ",
+                                          file, line);
                else
                        locn[0] = '\0';
 
@@ -336,7 +350,7 @@ void print_log(int level, const char *file, int line, int dm_errno,
        if (level > debug_level())
                return;
 
-       if (_log_to_file && (_log_while_suspended || !memlock())) {
+       if (_log_to_file && (_log_while_suspended || !critical_section())) {
                fprintf(_log_file, "%s:%d %s%s", file, line, log_command_name(),
                        _msg_prefix);
 
@@ -348,14 +362,14 @@ void print_log(int level, const char *file, int line, int dm_errno,
                fflush(_log_file);
        }
 
-       if (_syslog && (_log_while_suspended || !memlock())) {
+       if (_syslog && (_log_while_suspended || !critical_section())) {
                va_start(ap, format);
                vsyslog(level, trformat, ap);
                va_end(ap);
        }
 
        /* FIXME This code is unfinished - pre-extend & condense. */
-       if (!_already_logging && _log_direct && memlock()) {
+       if (!_already_logging && _log_direct && critical_section()) {
                _already_logging = 1;
                memset(&buf, ' ', sizeof(buf));
                bufused = 0;
@@ -372,8 +386,8 @@ void print_log(int level, const char *file, int line, int dm_errno,
                va_end(ap);
                bufused += n;
 
-             done:
                buf[bufused - 1] = '\n';
+             done:
                buf[bufused] = '\n';
                buf[sizeof(buf) - 1] = '\n';
                /* FIXME real size bufused */
index 10f34be733b4afee0c5a2f8ef43064445ce46cf6..f0da64f3d0c052c46309fc6a9ea9585255ae7035 100644 (file)
@@ -68,6 +68,7 @@
 #define log_very_verbose(args...) log_info(args)
 #define log_verbose(args...) log_notice(args)
 #define log_print(args...) LOG_LINE(_LOG_WARN, args)
+#define log_print_unless_silent(args...) LOG_LINE(silent_mode() ? _LOG_NOTICE : _LOG_WARN, args)
 #define log_error(args...) log_err(args)
 #define log_error_suppress(s, args...) log_err_suppress(s, args)
 #define log_error_once(args...) log_err_once(args)
@@ -76,6 +77,8 @@
 /* System call equivalents */
 #define log_sys_error(x, y) \
                log_err("%s: %s failed: %s", y, x, strerror(errno))
+#define log_sys_error_suppress(s, x, y) \
+               log_err_suppress(s, "%s: %s failed: %s", y, x, strerror(errno))
 #define log_sys_very_verbose(x, y) \
                log_info("%s: %s failed: %s", y, x, strerror(errno))
 #define log_sys_debug(x, y) \
index 4e7d9dc0b181686b6a562827a35aa2a5467170e2..4032f347c304426aa663b22151671133579d822d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
 #include "segtype.h"
 #include "str_list.h"
 
+#include <time.h>
+#include <sys/utsname.h>
+
+static struct utsname _utsname;
+static int _utsinit = 0;
+
+static char *_format_pvsegs(struct dm_pool *mem, const struct lv_segment *seg,
+                            int range_format)
+{
+       unsigned int s;
+       const char *name = NULL;
+       uint32_t extent = 0;
+       char extent_str[32];
+
+       if (!dm_pool_begin_object(mem, 256)) {
+               log_error("dm_pool_begin_object failed");
+               return NULL;
+       }
+
+       for (s = 0; s < seg->area_count; s++) {
+               switch (seg_type(seg, s)) {
+               case AREA_LV:
+                       name = seg_lv(seg, s)->name;
+                       extent = seg_le(seg, s);
+                       break;
+               case AREA_PV:
+                       name = dev_name(seg_dev(seg, s));
+                       extent = seg_pe(seg, s);
+                       break;
+               case AREA_UNASSIGNED:
+                       name = "unassigned";
+                       extent = 0;
+                       break;
+               default:
+                       log_error(INTERNAL_ERROR "Unknown area segtype.");
+                       return NULL;
+               }
+
+               if (!dm_pool_grow_object(mem, name, strlen(name))) {
+                       log_error("dm_pool_grow_object failed");
+                       return NULL;
+               }
+
+               if (dm_snprintf(extent_str, sizeof(extent_str),
+                               "%s%" PRIu32 "%s",
+                               range_format ? ":" : "(", extent,
+                               range_format ? "-"  : ")") < 0) {
+                       log_error("Extent number dm_snprintf failed");
+                       return NULL;
+               }
+               if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) {
+                       log_error("dm_pool_grow_object failed");
+                       return NULL;
+               }
+
+               if (range_format) {
+                       if (dm_snprintf(extent_str, sizeof(extent_str),
+                                       "%" PRIu32, extent + seg->area_len - 1) < 0) {
+                               log_error("Extent number dm_snprintf failed");
+                               return NULL;
+                       }
+                       if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) {
+                               log_error("dm_pool_grow_object failed");
+                               return NULL;
+                       }
+               }
+
+               if ((s != seg->area_count - 1) &&
+                   !dm_pool_grow_object(mem, range_format ? " " : ",", 1)) {
+                       log_error("dm_pool_grow_object failed");
+                       return NULL;
+               }
+       }
+
+       if (!dm_pool_grow_object(mem, "\0", 1)) {
+               log_error("dm_pool_grow_object failed");
+               return NULL;
+       }
+
+       return dm_pool_end_object(mem);
+}
+
+char *lvseg_devices(struct dm_pool *mem, const struct lv_segment *seg)
+{
+       return _format_pvsegs(mem, seg, 0);
+}
+
+char *lvseg_seg_pe_ranges(struct dm_pool *mem, const struct lv_segment *seg)
+{
+       return _format_pvsegs(mem, seg, 1);
+}
+
 char *lvseg_tags_dup(const struct lv_segment *seg)
 {
        return tags_format_and_copy(seg->lv->vg->vgmem, &seg->tags);
 }
 
-char *lvseg_segtype_dup(const struct lv_segment *seg)
+char *lvseg_segtype_dup(struct dm_pool *mem, const struct lv_segment *seg)
 {
-       if (seg->area_count == 1) {
-               return (char *)"linear";
-       }
-
-       return dm_pool_strdup(seg->lv->vg->vgmem, seg->segtype->ops->name(seg));
+       return dm_pool_strdup(mem, seg->segtype->ops->name(seg));
 }
 
 uint64_t lvseg_chunksize(const struct lv_segment *seg)
@@ -41,8 +129,11 @@ uint64_t lvseg_chunksize(const struct lv_segment *seg)
 
        if (lv_is_cow(seg->lv))
                size = (uint64_t) find_cow(seg->lv)->chunk_size;
+       else if (lv_is_thin_pool(seg->lv))
+               size = (uint64_t) seg->chunk_size;
        else
                size = UINT64_C(0);
+
        return size;
 }
 
@@ -69,6 +160,10 @@ char *lv_origin_dup(struct dm_pool *mem, const struct logical_volume *lv)
 {
        if (lv_is_cow(lv))
                return lv_name_dup(mem, origin_from_cow(lv));
+
+       if (lv_is_thin_volume(lv) && first_seg(lv)->origin)
+               return lv_name_dup(mem, first_seg(lv)->origin);
+
        return NULL;
 }
 
@@ -95,14 +190,36 @@ char *lv_mirror_log_dup(struct dm_pool *mem, const struct logical_volume *lv)
 {
        struct lv_segment *seg;
 
-       dm_list_iterate_items(seg, &lv->segments) {
-               if (!seg_is_mirrored(seg) || !seg->log_lv)
-                       continue;
-               return dm_pool_strdup(mem, seg->log_lv->name);
-       }
+       dm_list_iterate_items(seg, &lv->segments)
+               if (seg_is_mirrored(seg) && seg->log_lv)
+                       return dm_pool_strdup(mem, seg->log_lv->name);
+
+       return NULL;
+}
+
+char *lv_pool_lv_dup(struct dm_pool *mem, const struct logical_volume *lv)
+{
+       struct lv_segment *seg;
+
+       dm_list_iterate_items(seg, &lv->segments)
+               if (seg_is_thin_volume(seg) && seg->pool_lv)
+                       return dm_pool_strdup(mem, seg->pool_lv->name);
+
        return NULL;
 }
 
+char *lv_data_lv_dup(struct dm_pool *mem, const struct logical_volume *lv)
+{
+       return lv_is_thin_pool(lv) ?
+               dm_pool_strdup(mem, seg_lv(first_seg(lv), 0)->name) : NULL;
+}
+
+char *lv_metadata_lv_dup(struct dm_pool *mem, const struct logical_volume *lv)
+{
+       return lv_is_thin_pool(lv) ?
+               dm_pool_strdup(mem, first_seg(lv)->metadata_lv->name) : NULL;
+}
+
 int lv_kernel_minor(const struct logical_volume *lv)
 {
        struct lvinfo info;
@@ -155,11 +272,19 @@ uint64_t lv_origin_size(const struct logical_volume *lv)
        return 0;
 }
 
+uint64_t lv_metadata_size(const struct logical_volume *lv)
+{
+       return lv_is_thin_pool(lv) ? first_seg(lv)->metadata_lv->size : 0;
+}
+
 char *lv_path_dup(struct dm_pool *mem, const struct logical_volume *lv)
 {
        char *repstr;
        size_t len;
 
+       if (!*lv->vg->name)
+               return dm_pool_strdup(mem, "");
+
        len = strlen(lv->vg->cmd->dev_dir) + strlen(lv->vg->name) +
                strlen(lv->name) + 2;
 
@@ -173,6 +298,7 @@ char *lv_path_dup(struct dm_pool *mem, const struct logical_volume *lv)
                log_error("lvpath snprintf failed");
                return 0;
        }
+
        return repstr;
 }
 
@@ -206,13 +332,56 @@ static int _lv_mimage_in_sync(const struct logical_volume *lv)
        return (percent == PERCENT_100) ? 1 : 0;
 }
 
+static int _lv_raid_image_in_sync(const struct logical_volume *lv)
+{
+       percent_t percent;
+       struct lv_segment *raid_seg;
+
+       if (!(lv->status & RAID_IMAGE)) {
+               log_error(INTERNAL_ERROR "%s is not a RAID image", lv->name);
+               return 0;
+       }
+
+       raid_seg = get_only_segment_using_this_lv(first_seg(lv)->lv);
+       if (!raid_seg) {
+               log_error("Failed to find RAID segment for %s", lv->name);
+               return 0;
+       }
+
+       if (!seg_is_raid(raid_seg)) {
+               log_error("%s on %s is not a RAID segment",
+                         raid_seg->lv->name, lv->name);
+               return 0;
+       }
+
+       if (!lv_raid_percent(raid_seg->lv, &percent))
+               return_0;
+
+       if (percent == PERCENT_100)
+               return 1;
+
+       /*
+        * FIXME:  Get individual RAID image status.
+        * The status health characters reported from a RAID target
+        * indicate whether the whole array or just individual devices
+        * are in-sync.  If the corresponding character for this image
+        * was 'A', we could report a more accurate status.  This is
+        * especially so in the case of failures or rebuildings.
+        *
+        * We need to test the health characters anyway to report
+        * the correct 4th attr character.  Just need to figure out
+        * where to put this functionality.
+        */
+       return 0;
+}
 char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv)
 {
        percent_t snap_percent;
        struct lvinfo info;
+       struct lv_segment *seg;
        char *repstr;
 
-       if (!(repstr = dm_pool_zalloc(mem, 7))) {
+       if (!(repstr = dm_pool_zalloc(mem, 10))) {
                log_error("dm_pool_alloc failed");
                return 0;
        }
@@ -225,16 +394,27 @@ char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv)
                repstr[0] = 'p';
        else if (lv->status & CONVERTING)
                repstr[0] = 'c';
+       /* Origin takes precedence over mirror and thin volume */
+       else if (lv_is_origin(lv))
+               repstr[0] = (lv_is_merging_origin(lv)) ? 'O' : 'o';
+       else if (lv->status & RAID)
+               repstr[0] = (lv->status & LV_NOTSYNCED) ? 'R' : 'r';
+       else if (lv->status & MIRRORED)
+               repstr[0] = (lv->status & LV_NOTSYNCED) ? 'M' : 'm';
+       else if (lv_is_thin_volume(lv))
+               repstr[0] = 'V';
        else if (lv->status & VIRTUAL)
                repstr[0] = 'v';
-       /* Origin takes precedence over Mirror */
-       else if (lv_is_origin(lv)) {
-               repstr[0] = (lv_is_merging_origin(lv)) ? 'O' : 'o';
-       }
-       else if (lv->status & MIRRORED) {
-               repstr[0] = (lv->status & MIRROR_NOTSYNCED) ? 'M' : 'm';
-       }else if (lv->status & MIRROR_IMAGE)
+       else if (lv_is_thin_pool(lv))
+               repstr[0] = 't';
+       else if (lv_is_thin_pool_data(lv))
+               repstr[0] = 'T';
+       else if (lv_is_thin_pool_metadata(lv) || (lv->status & RAID_META))
+               repstr[0] = 'e';
+       else if (lv->status & MIRROR_IMAGE)
                repstr[0] = (_lv_mimage_in_sync(lv)) ? 'i' : 'I';
+       else if (lv->status & RAID_IMAGE)
+               repstr[0] = (_lv_raid_image_in_sync(lv)) ? 'i' : 'I';
        else if (lv->status & MIRROR_LOG)
                repstr[0] = 'l';
        else if (lv_is_cow(lv)) {
@@ -269,21 +449,117 @@ char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv)
                        repstr[4] = 'd';        /* Inactive without table */
 
                /* Snapshot dropped? */
-               if (info.live_table && lv_is_cow(lv) &&
-                   (!lv_snapshot_percent(lv, &snap_percent) ||
-                    snap_percent == PERCENT_INVALID)) {
-                       repstr[0] = toupper(repstr[0]);
-                       if (info.suspended)
-                               repstr[4] = 'S'; /* Susp Inv snapshot */
-                       else
-                               repstr[4] = 'I'; /* Invalid snapshot */
+               if (info.live_table && lv_is_cow(lv)) {
+                       if (!lv_snapshot_percent(lv, &snap_percent) ||
+                           snap_percent == PERCENT_INVALID) {
+                               if (info.suspended)
+                                       repstr[4] = 'S'; /* Susp Inv snapshot */
+                               else
+                                       repstr[4] = 'I'; /* Invalid snapshot */
+                       }
+                       else if (snap_percent == PERCENT_MERGE_FAILED) {
+                               if (info.suspended)
+                                       repstr[4] = 'M'; /* Susp snapshot merge failed */
+                               else
+                                       repstr[4] = 'm'; /* snapshot merge failed */
+                       }
                }
 
+               /*
+                * 'R' indicates read-only activation of a device that
+                * does not have metadata flagging it as read-only.
+                */
+               if (repstr[1] != 'r' && info.read_only)
+                       repstr[1] = 'R';
+
                repstr[5] = (info.open_count) ? 'o' : '-';
        } else {
                repstr[4] = '-';
                repstr[5] = '-';
        }
+
+       if (lv_is_thin_type(lv))
+               repstr[6] = 't';
+       else if (lv_is_raid_type(lv))
+               repstr[6] = 'r';
+       else if (lv_is_mirror_type(lv))
+               repstr[6] = 'm';
+       else if (lv_is_cow(lv) || lv_is_origin(lv))
+               repstr[6] = 's';
+       else if (lv_has_unknown_segments(lv))
+               repstr[6] = 'u';
+       else if (lv_is_virtual(lv))
+               repstr[6] = 'v';
+       else
+               repstr[6] = '-';
+
+       if (((lv_is_thin_volume(lv) && (seg = first_seg(lv)) && seg->pool_lv && (seg = first_seg(seg->pool_lv))) ||
+            (lv_is_thin_pool(lv) && (seg = first_seg(lv)))) &&
+           seg->zero_new_blocks)
+               repstr[7] = 'z';
+       else
+               repstr[7] = '-';
+
+       if (lv->status & PARTIAL_LV)
+               repstr[8] = 'p';
+       else
+               repstr[8] = '-';
+
 out:
        return repstr;
 }
+
+int lv_set_creation(struct logical_volume *lv,
+                   const char *hostname, uint64_t timestamp)
+{
+       const char *hn;
+
+       if (!hostname) {
+               if (!_utsinit) {
+                       if (uname(&_utsname)) {
+                               log_error("uname failed: %s", strerror(errno));
+                               memset(&_utsname, 0, sizeof(_utsname));
+                       }
+
+                       _utsinit = 1;
+               }
+
+               hostname = _utsname.nodename;
+       }
+
+       if (!(hn = dm_hash_lookup(lv->vg->hostnames, hostname))) {
+               if (!(hn = dm_pool_strdup(lv->vg->vgmem, hostname))) {
+                       log_error("Failed to duplicate hostname");
+                       return 0;
+               }
+
+               if (!dm_hash_insert(lv->vg->hostnames, hostname, (void*)hn))
+                       return_0;
+       }
+
+       lv->hostname = hn;
+       lv->timestamp = timestamp ? : (uint64_t) time(NULL);
+
+       return 1;
+}
+
+char *lv_time_dup(struct dm_pool *mem, const struct logical_volume *lv)
+{
+       char buffer[50];
+       struct tm *local_tm;
+       time_t ts = (time_t)lv->timestamp;
+
+       if (!ts ||
+           !(local_tm = localtime(&ts)) ||
+           /* FIXME: make this lvm.conf configurable */
+           !strftime(buffer, sizeof(buffer),
+                     "%Y-%m-%d %T %z", local_tm))
+               buffer[0] = 0;
+
+       return dm_pool_strdup(mem, buffer);
+}
+
+char *lv_host_dup(struct dm_pool *mem, const struct logical_volume *lv)
+{
+       return dm_pool_strdup(mem, lv->hostname ? : "");
+}
index bff36d280a9d06df990c75244bad62596ef7ffd1..0daab62d7105706cff2d8cdf27654112bd38d324 100644 (file)
@@ -23,7 +23,7 @@ struct replicator_device;
 
 struct logical_volume {
        union lvid lvid;
-       char *name;
+       const char *name;
 
        struct volume_group *vg;
 
@@ -46,9 +46,13 @@ struct logical_volume {
        struct dm_list segments;
        struct dm_list tags;
        struct dm_list segs_using_this_lv;
+
+       uint64_t timestamp;
+       const char *hostname;
 };
 
 uint64_t lv_size(const struct logical_volume *lv);
+uint64_t lv_metadata_size(const struct logical_volume *lv);
 char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv);
 char *lv_uuid_dup(const struct logical_volume *lv);
 char *lv_tags_dup(const struct logical_volume *lv);
@@ -59,6 +63,9 @@ char *lv_convert_lv_dup(struct dm_pool *mem, const struct logical_volume *lv);
 int lv_kernel_major(const struct logical_volume *lv);
 int lv_kernel_minor(const struct logical_volume *lv);
 char *lv_mirror_log_dup(struct dm_pool *mem, const struct logical_volume *lv);
+char *lv_data_lv_dup(struct dm_pool *mem, const struct logical_volume *lv);
+char *lv_metadata_lv_dup(struct dm_pool *mem, const struct logical_volume *lv);
+char *lv_pool_lv_dup(struct dm_pool *mem, const struct logical_volume *lv);
 char *lv_modules_dup(struct dm_pool *mem, const struct logical_volume *lv);
 char *lv_name_dup(struct dm_pool *mem, const struct logical_volume *lv);
 char *lv_origin_dup(struct dm_pool *mem, const struct logical_volume *lv);
@@ -66,7 +73,12 @@ uint32_t lv_kernel_read_ahead(const struct logical_volume *lv);
 uint64_t lvseg_start(const struct lv_segment *seg);
 uint64_t lvseg_size(const struct lv_segment *seg);
 uint64_t lvseg_chunksize(const struct lv_segment *seg);
-char *lvseg_segtype_dup(const struct lv_segment *seg);
+char *lvseg_segtype_dup(struct dm_pool *mem, const struct lv_segment *seg);
 char *lvseg_tags_dup(const struct lv_segment *seg);
-
+char *lvseg_devices(struct dm_pool *mem, const struct lv_segment *seg);
+char *lvseg_seg_pe_ranges(struct dm_pool *mem, const struct lv_segment *seg);
+char *lv_time_dup(struct dm_pool *mem, const struct logical_volume *lv);
+char *lv_host_dup(struct dm_pool *mem, const struct logical_volume *lv);
+int lv_set_creation(struct logical_volume *lv,
+                   const char *hostname, uint64_t timestamp);
 #endif /* _LVM_LV_H */
index 785a957ec6c768330d4d01cd9ea715356623465c..9f8e0e3ac19b4a1b35e2c016e90d630f7dc50a20 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.  
- * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
  */
 
 #ifndef _LVM_LV_ALLOC_H
+#define _LVM_LV_ALLOC_H
 
-struct lv_segment *alloc_lv_segment(struct dm_pool *mem,
-                                   const struct segment_type *segtype,
+struct lv_segment *alloc_lv_segment(const struct segment_type *segtype,
                                    struct logical_volume *lv,
                                    uint32_t le, uint32_t len,
                                    uint64_t status,
                                    uint32_t stripe_size,
                                    struct logical_volume *log_lv,
+                                   struct logical_volume *thin_pool_lv,
                                    uint32_t area_count,
                                    uint32_t area_len,
                                    uint32_t chunk_size,
@@ -39,8 +40,9 @@ int set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
                           uint64_t status);
 int move_lv_segment_area(struct lv_segment *seg_to, uint32_t area_to,
                         struct lv_segment *seg_from, uint32_t area_from);
-void release_lv_segment_area(struct lv_segment *seg, uint32_t s,
-                            uint32_t area_reduction);
+int release_lv_segment_area(struct lv_segment *seg, uint32_t s,
+                           uint32_t area_reduction);
+int release_and_discard_lv_segment_area(struct lv_segment *seg, uint32_t s, uint32_t area_reduction);
 
 struct alloc_handle;
 struct alloc_handle *allocate_extents(struct volume_group *vg,
@@ -72,12 +74,13 @@ int lv_add_mirror_lvs(struct logical_volume *lv,
 int lv_add_log_segment(struct alloc_handle *ah, uint32_t first_area,
                       struct logical_volume *log_lv, uint64_t status);
 int lv_add_virtual_segment(struct logical_volume *lv, uint64_t status,
-                           uint32_t extents, const struct segment_type *segtype);
+                           uint32_t extents,
+                          const struct segment_type *segtype,
+                          const char *thin_pool_name);
 
 void alloc_destroy(struct alloc_handle *ah);
 
-struct dm_list *build_parallel_areas_from_lv(struct cmd_context *cmd,
-                                            struct logical_volume *lv,
+struct dm_list *build_parallel_areas_from_lv(struct logical_volume *lv,
                                             unsigned use_pvmove_parent_lv);
 
 #endif
index 4a984a5981bf7eafc9fd76a24c61130bebb0be2a..d469fe85a6eff36d65f5d77f913f8cd23fd45eb7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
 #include "archiver.h"
 #include "activate.h"
 #include "str_list.h"
+#include "defaults.h"
+
+typedef enum {
+       PREFERRED,
+       USE_AREA,
+       NEXT_PV,
+       NEXT_AREA
+} area_use_t;
+
+/* FIXME: remove RAID_METADATA_AREA_LEN macro after defining 'raid_log_extents'*/
+#define RAID_METADATA_AREA_LEN 1
+
+/* FIXME These ended up getting used differently from first intended.  Refactor. */
+/* Only one of A_CONTIGUOUS_TO_LVSEG, A_CLING_TO_LVSEG, A_CLING_TO_ALLOCED may be set */
+#define A_CONTIGUOUS_TO_LVSEG  0x01    /* Must be contiguous to an existing segment */
+#define A_CLING_TO_LVSEG       0x02    /* Must use same disks as existing LV segment */
+#define A_CLING_TO_ALLOCED     0x04    /* Must use same disks as already-allocated segment */
+
+#define A_CLING_BY_TAGS                0x08    /* Must match tags against existing segment */
+#define A_CAN_SPLIT            0x10
+
+/*
+ * Constant parameters during a single allocation attempt.
+ */
+struct alloc_parms {
+       alloc_policy_t alloc;
+       unsigned flags;         /* Holds A_* */
+       struct lv_segment *prev_lvseg;
+       uint32_t extents_still_needed;
+};
+
+/*
+ * Holds varying state of each allocation attempt.
+ */
+struct alloc_state {
+       struct pv_area_used *areas;
+       uint32_t areas_size;
+       uint32_t log_area_count_still_needed;   /* Number of areas still needing to be allocated for the log */
+       uint32_t allocated;     /* Total number of extents allocated so far */
+};
 
 struct lv_names {
        const char *old;
@@ -99,7 +139,8 @@ struct lv_segment *get_only_segment_using_this_lv(struct logical_volume *lv)
                return NULL;
        }
 
-       sl = dm_list_item(dm_list_first(&lv->segs_using_this_lv), struct seg_list);
+       dm_list_iterate_items(sl, &lv->segs_using_this_lv)
+               break; /* first item */
 
        if (sl->count != 1) {
                log_error("%s is expected to have only one segment using it, "
@@ -139,13 +180,11 @@ static struct seg_pvs *_find_seg_pvs_by_le(struct dm_list *list, uint32_t le)
  */
 uint32_t find_free_lvnum(struct logical_volume *lv)
 {
-       int lvnum_used[MAX_RESTRICTED_LVS + 1];
+       int lvnum_used[MAX_RESTRICTED_LVS + 1] = { 0 };
        uint32_t i = 0;
        struct lv_list *lvl;
        int lvnum;
 
-       memset(&lvnum_used, 0, sizeof(lvnum_used));
-
        dm_list_iterate_items(lvl, &lv->vg->lvs) {
                lvnum = lvnum_from_lvid(&lvl->lv->lvid);
                if (lvnum <= MAX_RESTRICTED_LVS)
@@ -163,13 +202,13 @@ uint32_t find_free_lvnum(struct logical_volume *lv)
 /*
  * All lv_segments get created here.
  */
-struct lv_segment *alloc_lv_segment(struct dm_pool *mem,
-                                   const struct segment_type *segtype,
+struct lv_segment *alloc_lv_segment(const struct segment_type *segtype,
                                    struct logical_volume *lv,
                                    uint32_t le, uint32_t len,
                                    uint64_t status,
                                    uint32_t stripe_size,
                                    struct logical_volume *log_lv,
+                                   struct logical_volume *thin_pool_lv,
                                    uint32_t area_count,
                                    uint32_t area_len,
                                    uint32_t chunk_size,
@@ -178,8 +217,14 @@ struct lv_segment *alloc_lv_segment(struct dm_pool *mem,
                                    struct lv_segment *pvmove_source_seg)
 {
        struct lv_segment *seg;
+       struct dm_pool *mem = lv->vg->vgmem;
        uint32_t areas_sz = area_count * sizeof(*seg->areas);
 
+       if (!segtype) {
+               log_error(INTERNAL_ERROR "alloc_lv_segment: Missing segtype.");
+               return NULL;
+       }
+
        if (!(seg = dm_pool_zalloc(mem, sizeof(*seg))))
                return_NULL;
 
@@ -188,9 +233,10 @@ struct lv_segment *alloc_lv_segment(struct dm_pool *mem,
                return_NULL;
        }
 
-       if (!segtype) {
-               log_error("alloc_lv_segment: Missing segtype.");
-               return NULL;
+       if (segtype_is_raid(segtype) &&
+           !(seg->meta_areas = dm_pool_zalloc(mem, areas_sz))) {
+               dm_pool_free(mem, seg); /* frees everything alloced since seg */
+               return_NULL;
        }
 
        seg->segtype = segtype;
@@ -204,9 +250,22 @@ struct lv_segment *alloc_lv_segment(struct dm_pool *mem,
        seg->chunk_size = chunk_size;
        seg->region_size = region_size;
        seg->extents_copied = extents_copied;
-       seg->log_lv = log_lv;
        seg->pvmove_source_seg = pvmove_source_seg;
        dm_list_init(&seg->tags);
+       dm_list_init(&seg->thin_messages);
+
+       if (thin_pool_lv) {
+               /* If this thin volume, thin snapshot is being created */
+               if (lv_is_thin_volume(thin_pool_lv)) {
+                       seg->transaction_id = first_seg(first_seg(thin_pool_lv)->pool_lv)->transaction_id;
+                       if (!attach_pool_lv(seg, first_seg(thin_pool_lv)->pool_lv, thin_pool_lv))
+                               return_NULL;
+               } else {
+                       seg->transaction_id = first_seg(thin_pool_lv)->transaction_id;
+                       if (!attach_pool_lv(seg, thin_pool_lv, NULL))
+                               return_NULL;
+               }
+       }
 
        if (log_lv && !attach_mirror_log(seg, log_lv))
                return_NULL;
@@ -226,9 +285,9 @@ struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv,
                return NULL;
        }
 
-       if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, old_le_count,
+       if (!(seg = alloc_lv_segment(segtype, lv, old_le_count,
                                     lv->le_count - old_le_count, status, 0,
-                                    NULL, 0, lv->le_count - old_le_count,
+                                    NULL, NULL, 0, lv->le_count - old_le_count,
                                     0, 0, 0, NULL))) {
                log_error("Couldn't allocate new snapshot segment.");
                return NULL;
@@ -240,22 +299,60 @@ struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv,
        return seg;
 }
 
-void release_lv_segment_area(struct lv_segment *seg, uint32_t s,
-                            uint32_t area_reduction)
+static int _release_and_discard_lv_segment_area(struct lv_segment *seg, uint32_t s,
+                                               uint32_t area_reduction, int with_discard)
 {
        if (seg_type(seg, s) == AREA_UNASSIGNED)
-               return;
+               return 1;
 
        if (seg_type(seg, s) == AREA_PV) {
-               if (release_pv_segment(seg_pvseg(seg, s), area_reduction) &&
-                   seg->area_len == area_reduction)
+               if (with_discard && !discard_pv_segment(seg_pvseg(seg, s), area_reduction))
+                       return_0;
+
+               if (!release_pv_segment(seg_pvseg(seg, s), area_reduction))
+                       return_0;
+
+               if (seg->area_len == area_reduction)
                        seg_type(seg, s) = AREA_UNASSIGNED;
-               return;
+
+               return 1;
+       }
+
+       if ((seg_lv(seg, s)->status & MIRROR_IMAGE) ||
+           (seg_lv(seg, s)->status & THIN_POOL_DATA)) {
+               if (!lv_reduce(seg_lv(seg, s), area_reduction))
+                       return_0; /* FIXME: any upper level reporting */
+               return 1;
        }
 
-       if (seg_lv(seg, s)->status & MIRROR_IMAGE) {
+       if (seg_lv(seg, s)->status & RAID_IMAGE) {
+               /*
+                * FIXME: Use lv_reduce not lv_remove
+                *  We use lv_remove for now, because I haven't figured out
+                *  why lv_reduce won't remove the LV.
                lv_reduce(seg_lv(seg, s), area_reduction);
-               return;
+               */
+               if (area_reduction != seg->area_len) {
+                       log_error("Unable to reduce RAID LV - operation not implemented.");
+                       return_0;
+               } else {
+                       if (!lv_remove(seg_lv(seg, s))) {
+                               log_error("Failed to remove RAID image %s",
+                                         seg_lv(seg, s)->name);
+                               return 0;
+                       }
+               }
+
+               /* Remove metadata area if image has been removed */
+               if (area_reduction == seg->area_len) {
+                       if (!lv_reduce(seg_metalv(seg, s),
+                                      seg_metalv(seg, s)->le_count)) {
+                               log_error("Failed to remove RAID meta-device %s",
+                                         seg_metalv(seg, s)->name);
+                               return 0;
+                       }
+               }
+               return 1;
        }
 
        if (area_reduction == seg->area_len) {
@@ -269,6 +366,18 @@ void release_lv_segment_area(struct lv_segment *seg, uint32_t s,
                seg_le(seg, s) = 0;
                seg_type(seg, s) = AREA_UNASSIGNED;
        }
+
+       return 1;
+}
+
+int release_and_discard_lv_segment_area(struct lv_segment *seg, uint32_t s, uint32_t area_reduction)
+{
+       return _release_and_discard_lv_segment_area(seg, s, area_reduction, 1);
+}
+
+int release_lv_segment_area(struct lv_segment *seg, uint32_t s, uint32_t area_reduction)
+{
+       return _release_and_discard_lv_segment_area(seg, s, area_reduction, 0);
 }
 
 /*
@@ -286,9 +395,11 @@ int move_lv_segment_area(struct lv_segment *seg_to, uint32_t area_to,
                pv = seg_pv(seg_from, area_from);
                pe = seg_pe(seg_from, area_from);
 
-               release_lv_segment_area(seg_from, area_from,
-                                       seg_from->area_len);
-               release_lv_segment_area(seg_to, area_to, seg_to->area_len);
+               if (!release_lv_segment_area(seg_from, area_from, seg_from->area_len))
+                       return_0;
+
+               if (!release_lv_segment_area(seg_to, area_to, seg_to->area_len))
+                       return_0;
 
                if (!set_lv_segment_area_pv(seg_to, area_to, pv, pe))
                        return_0;
@@ -299,9 +410,11 @@ int move_lv_segment_area(struct lv_segment *seg_to, uint32_t area_to,
                lv = seg_lv(seg_from, area_from);
                le = seg_le(seg_from, area_from);
 
-               release_lv_segment_area(seg_from, area_from,
-                                       seg_from->area_len);
-               release_lv_segment_area(seg_to, area_to, seg_to->area_len);
+               if (!release_lv_segment_area(seg_from, area_from, seg_from->area_len))
+                       return_0;
+
+               if (!release_lv_segment_area(seg_to, area_to, seg_to->area_len))
+                       return_0;
 
                if (!set_lv_segment_area_lv(seg_to, area_to, lv, le, 0))
                        return_0;
@@ -309,7 +422,8 @@ int move_lv_segment_area(struct lv_segment *seg_to, uint32_t area_to,
                break;
 
        case AREA_UNASSIGNED:
-               release_lv_segment_area(seg_to, area_to, seg_to->area_len);
+               if (!release_lv_segment_area(seg_to, area_to, seg_to->area_len))
+                       return_0;
        }
 
        return 1;
@@ -340,9 +454,19 @@ int set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
        log_very_verbose("Stack %s:%" PRIu32 "[%" PRIu32 "] on LV %s:%" PRIu32,
                         seg->lv->name, seg->le, area_num, lv->name, le);
 
-       seg->areas[area_num].type = AREA_LV;
-       seg_lv(seg, area_num) = lv;
-       seg_le(seg, area_num) = le;
+       if (status & RAID_META) {
+               seg->meta_areas[area_num].type = AREA_LV;
+               seg_metalv(seg, area_num) = lv;
+               if (le) {
+                       log_error(INTERNAL_ERROR "Meta le != 0");
+                       return 0;
+               }
+               seg_metale(seg, area_num) = 0;
+       } else {
+               seg->areas[area_num].type = AREA_LV;
+               seg_lv(seg, area_num) = lv;
+               seg_le(seg, area_num) = le;
+       }
        lv->status |= status;
 
        if (!add_seg_to_segs_using_this_lv(lv, seg))
@@ -383,7 +507,7 @@ static int _lv_segment_reduce(struct lv_segment *seg, uint32_t reduction)
        if (seg_is_striped(seg)) {
                if (reduction % seg->area_count) {
                        log_error("Segment extent reduction %" PRIu32
-                                 "not divisible by #stripes %" PRIu32,
+                                 " not divisible by #stripes %" PRIu32,
                                  reduction, seg->area_count);
                        return 0;
                }
@@ -392,7 +516,8 @@ static int _lv_segment_reduce(struct lv_segment *seg, uint32_t reduction)
                area_reduction = reduction;
 
        for (s = 0; s < seg->area_count; s++)
-               release_lv_segment_area(seg, s, area_reduction);
+               if (!release_and_discard_lv_segment_area(seg, s, area_reduction))
+                       return_0;
 
        seg->len -= reduction;
        seg->area_len -= area_reduction;
@@ -418,6 +543,15 @@ static int _lv_reduce(struct logical_volume *lv, uint32_t extents, int delete)
                        /* FIXME Check this is safe */
                        if (seg->log_lv && !lv_remove(seg->log_lv))
                                return_0;
+
+                       if (seg->metadata_lv && !lv_remove(seg->metadata_lv))
+                               return_0;
+
+                       if (seg->pool_lv) {
+                               if (!detach_pool_lv(seg))
+                                       return_0;
+                       }
+
                        dm_list_del(&seg->list);
                        reduction = seg->len;
                } else
@@ -459,21 +593,23 @@ int replace_lv_with_error_segment(struct logical_volume *lv)
 {
        uint32_t len = lv->le_count;
 
-       if (!lv_empty(lv))
+       if (len && !lv_empty(lv))
                return_0;
 
+       /* Minimum size required for a table. */
+       if (!len)
+               len = 1;
+
        /*
         * Since we are replacing the whatever-was-there with
         * an error segment, we should also clear any flags
         * that suggest it is anything other than "error".
         */
-       lv->status &= ~MIRRORED;
+       lv->status &= ~(MIRRORED|PVMOVE);
 
        /* FIXME: Should we bug if we find a log_lv attached? */
 
-       if (!lv_add_virtual_segment(lv, 0, len,
-                                   get_segtype_from_string(lv->vg->cmd,
-                                                           "error")))
+       if (!lv_add_virtual_segment(lv, 0, len, get_segtype_from_string(lv->vg->cmd, "error"), NULL))
                return_0;
 
        return 1;
@@ -520,13 +656,27 @@ struct alloc_handle {
        alloc_policy_t alloc;           /* Overall policy */
        uint32_t new_extents;           /* Number of new extents required */
        uint32_t area_count;            /* Number of parallel areas */
+       uint32_t parity_count;   /* Adds to area_count, but not area_multiple */
        uint32_t area_multiple;         /* seg->len = area_len * area_multiple */
        uint32_t log_area_count;        /* Number of parallel logs */
-       uint32_t log_len;               /* Length of log */
+       uint32_t metadata_area_count;   /* Number of parallel metadata areas */
+       uint32_t log_len;               /* Length of log/metadata_area */
        uint32_t region_size;           /* Mirror region size */
        uint32_t total_area_len;        /* Total number of parallel extents */
 
-       const struct config_node *cling_tag_list_cn;
+       unsigned maximise_cling;
+       unsigned mirror_logs_separate;  /* Force mirror logs on separate PVs? */
+
+       /*
+        * RAID devices require a metadata area that accompanies each
+        * device.  During initial creation, it is best to look for space
+        * that is new_extents + log_len and then split that between two
+        * allocated areas when found.  'alloc_and_split_meta' indicates
+        * that this is the desired dynamic.
+        */
+       unsigned alloc_and_split_meta;
+
+       const struct dm_config_node *cling_tag_list_cn;
 
        struct dm_list *parallel_areas; /* PVs to avoid */
 
@@ -547,6 +697,27 @@ static uint32_t _calc_area_multiple(const struct segment_type *segtype,
        if (segtype_is_striped(segtype))
                return area_count;
 
+       /* Parity RAID (e.g. RAID 4/5/6) */
+       if (segtype_is_raid(segtype) && segtype->parity_devs) {
+               /*
+                * As articulated in _alloc_init, we can tell by
+                * the area_count whether a replacement drive is
+                * being allocated; and if this is the case, then
+                * there is no area_multiple that should be used.
+                */
+               if (area_count <= segtype->parity_devs)
+                       return 1;
+               return area_count - segtype->parity_devs;
+       }
+
+       /* RAID10 - only has 2-way mirror right now */
+       if (!strcmp(segtype->name, "raid10")) {
+               // FIXME: I'd like the 'stripes' arg always given
+               if (!stripes)
+                       return area_count / 2;
+               return stripes;
+       }
+
        /* Mirrored stripes */
        if (stripes)
                return stripes;
@@ -563,7 +734,7 @@ static uint32_t mirror_log_extents(uint32_t region_size, uint32_t pe_size, uint3
 {
        size_t area_size, bitset_size, log_size, region_count;
 
-       area_size = area_len * pe_size;
+       area_size = (size_t)area_len * pe_size;
        region_count = dm_div_up(area_size, region_size);
 
        /* Work out how many "unsigned long"s we need to hold the bitset. */
@@ -573,8 +744,21 @@ static uint32_t mirror_log_extents(uint32_t region_size, uint32_t pe_size, uint3
        /* Log device holds both header and bitset. */
        log_size = dm_round_up((MIRROR_LOG_OFFSET << SECTOR_SHIFT) + bitset_size, 1 << SECTOR_SHIFT);
        log_size >>= SECTOR_SHIFT;
+       log_size = dm_div_up(log_size, pe_size);
 
-       return dm_div_up(log_size, pe_size);
+       /*
+        * Kernel requires a mirror to be at least 1 region large.  So,
+        * if our mirror log is itself a mirror, it must be at least
+        * 1 region large.  This restriction may not be necessary for
+        * non-mirrored logs, but we apply the rule anyway.
+        *
+        * (The other option is to make the region size of the log
+        * mirror smaller than the mirror it is acting as a log for,
+        * but that really complicates things.  It's much easier to
+        * keep the region_size the same for both.)
+        */
+       return (log_size > (region_size / pe_size)) ? log_size :
+               (region_size / pe_size);
 }
 
 /*
@@ -589,13 +773,14 @@ static struct alloc_handle *_alloc_init(struct cmd_context *cmd,
                                        uint32_t new_extents,
                                        uint32_t mirrors,
                                        uint32_t stripes,
-                                       uint32_t log_area_count,
+                                       uint32_t metadata_area_count,
                                        uint32_t extent_size,
                                        uint32_t region_size,
                                        struct dm_list *parallel_areas)
 {
        struct alloc_handle *ah;
-       uint32_t s, area_count;
+       uint32_t s, area_count, alloc_count, parity_count;
+       size_t size = 0;
 
        /* FIXME Caller should ensure this */
        if (mirrors && !stripes)
@@ -608,7 +793,36 @@ static struct alloc_handle *_alloc_init(struct cmd_context *cmd,
        else
                area_count = stripes;
 
-       if (!(ah = dm_pool_zalloc(mem, sizeof(*ah) + sizeof(ah->alloced_areas[0]) * (area_count + log_area_count)))) {
+       size = sizeof(*ah);
+
+       /*
+        * It is a requirement that RAID 4/5/6 are created with a number of
+        * stripes that is greater than the number of parity devices.  (e.g
+        * RAID4/5 must have at least 2 stripes and RAID6 must have at least
+        * 3.)  It is also a constraint that, when replacing individual devices
+        * in a RAID 4/5/6 array, no more devices can be replaced than
+        * there are parity devices.  (Otherwise, there would not be enough
+        * redundancy to maintain the array.)  Understanding these two
+        * constraints allows us to infer whether the caller of this function
+        * is intending to allocate an entire array or just replacement
+        * component devices.  In the former case, we must account for the
+        * necessary parity_count.  In the later case, we do not need to
+        * account for the extra parity devices because the array already
+        * exists and they only want replacement drives.
+        */
+       parity_count = (area_count <= segtype->parity_devs) ? 0 :
+               segtype->parity_devs;
+       alloc_count = area_count + parity_count;
+       if (segtype_is_raid(segtype) && metadata_area_count)
+               /* RAID has a meta area for each device */
+               alloc_count *= 2;
+       else
+               /* mirrors specify their exact log count */
+               alloc_count += metadata_area_count;
+
+       size += sizeof(ah->alloced_areas[0]) * alloc_count;
+
+       if (!(ah = dm_pool_zalloc(mem, size))) {
                log_error("allocation handle allocation failed");
                return NULL;
        }
@@ -618,7 +832,7 @@ static struct alloc_handle *_alloc_init(struct cmd_context *cmd,
        if (segtype_is_virtual(segtype))
                return ah;
 
-       if (!(area_count + log_area_count)) {
+       if (!(area_count + metadata_area_count)) {
                log_error(INTERNAL_ERROR "_alloc_init called for non-virtual segment with no disk space.");
                return NULL;
        }
@@ -628,22 +842,69 @@ static struct alloc_handle *_alloc_init(struct cmd_context *cmd,
                return NULL;
        }
 
-       ah->new_extents = new_extents;
+       if (mirrors || stripes)
+               ah->new_extents = new_extents;
+       else
+               ah->new_extents = 0;
        ah->area_count = area_count;
-       ah->log_area_count = log_area_count;
+       ah->parity_count = parity_count;
        ah->region_size = region_size;
        ah->alloc = alloc;
-       ah->area_multiple = _calc_area_multiple(segtype, area_count, stripes);
 
-       ah->log_len = log_area_count ? mirror_log_extents(ah->region_size, extent_size, ah->new_extents / ah->area_multiple) : 0;
+       /*
+        * For the purposes of allocation, area_count and parity_count are
+        * kept separately.  However, the 'area_count' field in an
+        * lv_segment includes both; and this is what '_calc_area_multiple'
+        * is calculated from.  So, we must pass in the total count to get
+        * a correct area_multiple.
+        */
+       ah->area_multiple = _calc_area_multiple(segtype, area_count + parity_count, stripes);
+       ah->mirror_logs_separate = find_config_tree_bool(cmd, "allocation/mirror_logs_require_separate_pvs",
+                                                        DEFAULT_MIRROR_LOGS_REQUIRE_SEPARATE_PVS);
+
+       if (segtype_is_raid(segtype)) {
+               if (metadata_area_count) {
+                       if (metadata_area_count != area_count)
+                               log_error(INTERNAL_ERROR
+                                         "Bad metadata_area_count");
+                       ah->metadata_area_count = area_count;
+                       ah->alloc_and_split_meta = 1;
+
+                       ah->log_len = RAID_METADATA_AREA_LEN;
+
+                       /*
+                        * We need 'log_len' extents for each
+                        * RAID device's metadata_area
+                        */
+                       ah->new_extents += (ah->log_len * ah->area_multiple);
+               } else {
+                       ah->log_area_count = 0;
+                       ah->log_len = 0;
+               }
+       } else if (segtype_is_thin_pool(segtype)) {
+               ah->log_area_count = metadata_area_count;
+               /* thin_pool uses region_size to pass metadata size in extents */
+               ah->log_len = ah->region_size;
+               ah->region_size = 0;
+               ah->mirror_logs_separate =
+                       find_config_tree_bool(cmd, "allocation/thin_pool_metadata_require_separate_pvs",
+                                             DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS);
+       } else {
+               ah->log_area_count = metadata_area_count;
+               ah->log_len = !metadata_area_count ? 0 :
+                       mirror_log_extents(ah->region_size, extent_size,
+                                          new_extents / ah->area_multiple);
+       }
 
-       for (s = 0; s < ah->area_count + ah->log_area_count; s++)
+       for (s = 0; s < alloc_count; s++)
                dm_list_init(&ah->alloced_areas[s]);
 
        ah->parallel_areas = parallel_areas;
 
        ah->cling_tag_list_cn = find_config_tree_node(cmd, "allocation/cling_tag_list");
 
+       ah->maximise_cling = find_config_tree_bool(cmd, "allocation/maximise_cling", DEFAULT_MAXIMISE_CLING);
+
        return ah;
 }
 
@@ -653,6 +914,78 @@ void alloc_destroy(struct alloc_handle *ah)
                dm_pool_destroy(ah->mem);
 }
 
+/* Is there enough total space or should we give up immediately? */
+static int _sufficient_pes_free(struct alloc_handle *ah, struct dm_list *pvms,
+                               uint32_t allocated, uint32_t extents_still_needed)
+{
+       uint32_t area_extents_needed = (extents_still_needed - allocated) * ah->area_count / ah->area_multiple;
+       uint32_t parity_extents_needed = (extents_still_needed - allocated) * ah->parity_count / ah->area_multiple;
+       uint32_t metadata_extents_needed = ah->metadata_area_count * RAID_METADATA_AREA_LEN; /* One each */
+       uint32_t total_extents_needed = area_extents_needed + parity_extents_needed + metadata_extents_needed;
+       uint32_t free_pes = pv_maps_size(pvms);
+
+       if (total_extents_needed > free_pes) {
+               log_error("Insufficient free space: %" PRIu32 " extents needed,"
+                         " but only %" PRIu32 " available",
+                         total_extents_needed, free_pes);
+               return 0;
+       }
+
+       return 1;
+}
+
+/* For striped mirrors, all the areas are counted, through the mirror layer */
+static uint32_t _stripes_per_mimage(struct lv_segment *seg)
+{
+       struct lv_segment *last_lvseg;
+
+       if (seg_is_mirrored(seg) && seg->area_count && seg_type(seg, 0) == AREA_LV) {
+               last_lvseg = dm_list_item(dm_list_last(&seg_lv(seg, 0)->segments), struct lv_segment);
+               if (seg_is_striped(last_lvseg))
+                       return last_lvseg->area_count;
+       }
+
+       return 1;
+}
+
+static void _init_alloc_parms(struct alloc_handle *ah, struct alloc_parms *alloc_parms, alloc_policy_t alloc,
+                             struct lv_segment *prev_lvseg, unsigned can_split,
+                             uint32_t allocated, uint32_t extents_still_needed)
+{
+       alloc_parms->alloc = alloc;
+       alloc_parms->prev_lvseg = prev_lvseg;
+       alloc_parms->flags = 0;
+       alloc_parms->extents_still_needed = extents_still_needed;
+
+       /* Are there any preceding segments we must follow on from? */
+       if (alloc_parms->prev_lvseg) {
+               if (alloc_parms->alloc == ALLOC_CONTIGUOUS)
+                       alloc_parms->flags |= A_CONTIGUOUS_TO_LVSEG;
+               else if ((alloc_parms->alloc == ALLOC_CLING) || (alloc_parms->alloc == ALLOC_CLING_BY_TAGS))
+                       alloc_parms->flags |= A_CLING_TO_LVSEG;
+       } else
+               /*
+                * A cling allocation that follows a successful contiguous allocation
+                * must use the same PVs (or else fail).
+                */
+               if ((alloc_parms->alloc == ALLOC_CLING) || (alloc_parms->alloc == ALLOC_CLING_BY_TAGS))
+                       alloc_parms->flags |= A_CLING_TO_ALLOCED;
+
+       if (alloc_parms->alloc == ALLOC_CLING_BY_TAGS)
+               alloc_parms->flags |= A_CLING_BY_TAGS;
+
+       /*
+        * For normal allocations, if any extents have already been found 
+        * for allocation, prefer to place further extents on the same disks as
+        * have already been used.
+        */
+       if (ah->maximise_cling && alloc_parms->alloc == ALLOC_NORMAL && allocated != alloc_parms->extents_still_needed)
+               alloc_parms->flags |= A_CLING_TO_ALLOCED;
+
+       if (can_split)
+               alloc_parms->flags |= A_CAN_SPLIT;
+}
+
 static int _log_parallel_areas(struct dm_pool *mem, struct dm_list *parallel_areas)
 {
        struct seg_pvs *spvs;
@@ -708,10 +1041,9 @@ static int _setup_alloced_segment(struct logical_volume *lv, uint64_t status,
 
        area_multiple = _calc_area_multiple(segtype, area_count, 0);
 
-       if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv,
-                                    lv->le_count,
+       if (!(seg = alloc_lv_segment(segtype, lv, lv->le_count,
                                     aa[0].len * area_multiple,
-                                    status, stripe_size, NULL,
+                                    status, stripe_size, NULL, NULL,
                                     area_count,
                                     aa[0].len, 0u, region_size, 0u, NULL))) {
                log_error("Couldn't allocate new LV segment.");
@@ -759,30 +1091,33 @@ static int _setup_alloced_segments(struct logical_volume *lv,
  * If the complete area is not needed then it gets split.
  * The part used is removed from the pv_map so it can't be allocated twice.
  */
-static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t needed,
-                               struct pv_area_used *areas, uint32_t *allocated,
-                               unsigned log_needs_allocating, uint32_t ix_log_offset)
+static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t max_to_allocate,
+                               struct alloc_state *alloc_state, uint32_t ix_log_offset)
 {
-       uint32_t area_len, len, remaining;
+       uint32_t area_len, len;
        uint32_t s;
        uint32_t ix_log_skip = 0; /* How many areas to skip in middle of array to reach log areas */
-       uint32_t total_area_count = ah->area_count + (log_needs_allocating ? ah->log_area_count : 0);
+       uint32_t total_area_count;
        struct alloced_area *aa;
+       struct pv_area *pva;
 
+       total_area_count = ah->area_count + alloc_state->log_area_count_still_needed;
+       total_area_count += ah->parity_count;
        if (!total_area_count) {
                log_error(INTERNAL_ERROR "_alloc_parallel_area called without any allocation to do.");
                return 1;
        }
 
-       remaining = needed - *allocated;
-       area_len = remaining / ah->area_multiple;
+       area_len = max_to_allocate / ah->area_multiple;
 
        /* Reduce area_len to the smallest of the areas */
-       for (s = 0; s < ah->area_count; s++)
-               if (area_len > areas[s].used)
-                       area_len = areas[s].used;
+       for (s = 0; s < ah->area_count + ah->parity_count; s++)
+               if (area_len > alloc_state->areas[s].used)
+                       area_len = alloc_state->areas[s].used;
 
-       if (!(aa = dm_pool_alloc(ah->mem, sizeof(*aa) * total_area_count))) {
+       len = (ah->alloc_and_split_meta) ? total_area_count * 2 : total_area_count;
+       len *= sizeof(*aa);
+       if (!(aa = dm_pool_alloc(ah->mem, len))) {
                log_error("alloced_area allocation failed");
                return 0;
        }
@@ -794,41 +1129,61 @@ static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t needed,
         */
        len = area_len;
        for (s = 0; s < total_area_count; s++) {
-               if (s == ah->area_count) {
+               if (s == (ah->area_count + ah->parity_count)) {
                        ix_log_skip = ix_log_offset - ah->area_count;
                        len = ah->log_len;
                }
 
-               aa[s].pv = areas[s + ix_log_skip].pva->map->pv;
-               aa[s].pe = areas[s + ix_log_skip].pva->start;
-               aa[s].len = len;
+               pva = alloc_state->areas[s + ix_log_skip].pva;
+               if (ah->alloc_and_split_meta) {
+                       /*
+                        * The metadata area goes at the front of the allocated
+                        * space for now, but could easily go at the end (or
+                        * middle!).
+                        *
+                        * Even though we split these two from the same
+                        * allocation, we store the images at the beginning
+                        * of the areas array and the metadata at the end.
+                        */
+                       s += ah->area_count + ah->parity_count;
+                       aa[s].pv = pva->map->pv;
+                       aa[s].pe = pva->start;
+                       aa[s].len = ah->log_len;
+
+                       log_debug("Allocating parallel metadata area %" PRIu32
+                                 " on %s start PE %" PRIu32
+                                 " length %" PRIu32 ".",
+                                 (s - (ah->area_count + ah->parity_count)),
+                                 pv_dev_name(aa[s].pv), aa[s].pe,
+                                 ah->log_len);
+
+                       consume_pv_area(pva, ah->log_len);
+                       dm_list_add(&ah->alloced_areas[s], &aa[s].list);
+                       s -= ah->area_count + ah->parity_count;
+               }
+               aa[s].len = (ah->alloc_and_split_meta) ? len - ah->log_len : len;
+               /* Skip empty allocations */
+               if (!aa[s].len)
+                       continue;
+
+               aa[s].pv = pva->map->pv;
+               aa[s].pe = pva->start;
 
                log_debug("Allocating parallel area %" PRIu32
                          " on %s start PE %" PRIu32 " length %" PRIu32 ".",
-                         s, dev_name(aa[s].pv->dev), aa[s].pe, len);
+                         s, pv_dev_name(aa[s].pv), aa[s].pe, aa[s].len);
 
-               consume_pv_area(areas[s + ix_log_skip].pva, len);
+               consume_pv_area(pva, aa[s].len);
 
                dm_list_add(&ah->alloced_areas[s], &aa[s].list);
        }
 
-       ah->total_area_len += area_len;
-
-       *allocated += area_len * ah->area_multiple;
+       /* Only need to alloc metadata from the first batch */
+       ah->alloc_and_split_meta = 0;
 
-       return 1;
-}
-
-/* For striped mirrors, all the areas are counted, through the mirror layer */
-static uint32_t _stripes_per_mimage(struct lv_segment *seg)
-{
-       struct lv_segment *last_lvseg;
+       ah->total_area_len += area_len;
 
-       if (seg_is_mirrored(seg) && seg->area_count && seg_type(seg, 0) == AREA_LV) {
-               last_lvseg = dm_list_item(dm_list_last(&seg_lv(seg, 0)->segments), struct lv_segment);
-               if (seg_is_striped(last_lvseg))
-                       return last_lvseg->area_count;
-       }
+       alloc_state->allocated += area_len * ah->area_multiple;
 
        return 1;
 }
@@ -887,7 +1242,7 @@ static int _for_each_pv(struct cmd_context *cmd, struct logical_volume *lv,
                                               (le - seg->le) / area_multiple,
                                               area_len, NULL, max_seg_len, 0,
                                               (stripes_per_mimage == 1) && only_single_area_segments ? 1U : 0U,
-                                              top_level_area_index != -1 ? top_level_area_index : (int) s * stripes_per_mimage,
+                                              (top_level_area_index != -1) ? top_level_area_index : (int) (s * stripes_per_mimage),
                                               only_single_area_segments, fn,
                                               data)))
                                stack;
@@ -936,7 +1291,7 @@ struct pv_match {
        struct pv_area_used *areas;
        struct pv_area *pva;
        uint32_t areas_size;
-       const struct config_node *cling_tag_list_cn;
+       const struct dm_config_node *cling_tag_list_cn;
        int s;  /* Area index of match */
 };
 
@@ -955,14 +1310,14 @@ static int _is_same_pv(struct pv_match *pvmatch __attribute((unused)), struct pv
  * Does PV area have a tag listed in allocation/cling_tag_list that 
  * matches a tag of the PV of the existing segment?
  */
-static int _has_matching_pv_tag(struct pv_match *pvmatch, struct pv_segment *pvseg, struct pv_area *pva)
+static int _pvs_have_matching_tag(const struct dm_config_node *cling_tag_list_cn, struct physical_volume *pv1, struct physical_volume *pv2)
 {
-       const struct config_value *cv;
+       const struct dm_config_value *cv;
        const char *str;
        const char *tag_matched;
 
-       for (cv = pvmatch->cling_tag_list_cn->v; cv; cv = cv->next) {
-               if (cv->type != CFG_STRING) {
+       for (cv = cling_tag_list_cn->v; cv; cv = cv->next) {
+               if (cv->type != DM_CFG_STRING) {
                        log_error("Ignoring invalid string in config file entry "
                                  "allocation/cling_tag_list");
                        continue;
@@ -990,21 +1345,21 @@ static int _has_matching_pv_tag(struct pv_match *pvmatch, struct pv_segment *pvs
 
                /* Wildcard matches any tag against any tag. */
                if (!strcmp(str, "*")) {
-                       if (!str_list_match_list(&pvseg->pv->tags, &pva->map->pv->tags, &tag_matched))
+                       if (!str_list_match_list(&pv1->tags, &pv2->tags, &tag_matched))
                                continue;
                        else {
                                log_debug("Matched allocation PV tag %s on existing %s with free space on %s.",
-                                         tag_matched, pv_dev_name(pvseg->pv), pv_dev_name(pva->map->pv));
+                                         tag_matched, pv_dev_name(pv1), pv_dev_name(pv2));
                                return 1;
                        }
                }
 
-               if (!str_list_match_item(&pvseg->pv->tags, str) ||
-                   !str_list_match_item(&pva->map->pv->tags, str))
+               if (!str_list_match_item(&pv1->tags, str) ||
+                   !str_list_match_item(&pv2->tags, str))
                        continue;
                else {
                        log_debug("Matched allocation PV tag %s on existing %s with free space on %s.",
-                                 str, pv_dev_name(pvseg->pv), pv_dev_name(pva->map->pv));
+                                 str, pv_dev_name(pv1), pv_dev_name(pv2));
                        return 1;
                }
        }
@@ -1012,6 +1367,11 @@ static int _has_matching_pv_tag(struct pv_match *pvmatch, struct pv_segment *pvs
        return 0;
 }
 
+static int _has_matching_pv_tag(struct pv_match *pvmatch, struct pv_segment *pvseg, struct pv_area *pva)
+{
+       return _pvs_have_matching_tag(pvmatch->cling_tag_list_cn, pvseg->pv, pva->map->pv);
+}
+
 /*
  * Is PV area contiguous to PV segment?
  */
@@ -1026,12 +1386,28 @@ static int _is_contiguous(struct pv_match *pvmatch __attribute((unused)), struct
        return 1;
 }
 
+static void _reserve_area(struct pv_area_used *area_used, struct pv_area *pva, uint32_t required,
+                         uint32_t ix_pva, uint32_t unreserved)
+{
+       log_debug("%s allocation area %" PRIu32 " %s %s start PE %" PRIu32
+                 " length %" PRIu32 " leaving %" PRIu32 ".",
+                 area_used->pva ? "Changing   " : "Considering", 
+                 ix_pva - 1, area_used->pva ? "to" : "as", 
+                 dev_name(pva->map->pv->dev), pva->start, required, unreserved);
+
+       area_used->pva = pva;
+       area_used->used = required;
+}
+
 static int _is_condition(struct cmd_context *cmd __attribute__((unused)),
                         struct pv_segment *pvseg, uint32_t s,
                         void *data)
 {
        struct pv_match *pvmatch = data;
 
+       if (pvmatch->areas[s].pva)
+               return 1;       /* Area already assigned */
+
        if (!pvmatch->condition(pvmatch, pvseg, pvmatch->pva))
                return 1;       /* Continue */
 
@@ -1039,16 +1415,10 @@ static int _is_condition(struct cmd_context *cmd __attribute__((unused)),
                return 1;
 
        /*
-        * Only used for cling and contiguous policies so it's safe to say all
-        * the available space is used.
+        * Only used for cling and contiguous policies (which only make one allocation per PV)
+        * so it's safe to say all the available space is used.
         */
-       pvmatch->areas[s].pva = pvmatch->pva;
-       pvmatch->areas[s].used = pvmatch->pva->count;
-
-       log_debug("Trying allocation area %" PRIu32 " on %s start PE %" PRIu32
-                 " length %" PRIu32 ".",
-                 s, dev_name(pvmatch->pva->map->pv->dev), pvmatch->pva->start, 
-                 pvmatch->pva->count);
+       _reserve_area(&pvmatch->areas[s], pvmatch->pva, pvmatch->pva->count, s + 1, 0);
 
        return 2;       /* Finished */
 }
@@ -1056,23 +1426,33 @@ static int _is_condition(struct cmd_context *cmd __attribute__((unused)),
 /*
  * Is pva on same PV as any existing areas?
  */
-static int _check_cling(struct cmd_context *cmd,
-                       const struct config_node *cling_tag_list_cn,
+static int _check_cling(struct alloc_handle *ah,
+                       const struct dm_config_node *cling_tag_list_cn,
                        struct lv_segment *prev_lvseg, struct pv_area *pva,
-                       struct pv_area_used *areas, uint32_t areas_size)
+                       struct alloc_state *alloc_state)
 {
        struct pv_match pvmatch;
        int r;
+       uint32_t le, len;
 
        pvmatch.condition = cling_tag_list_cn ? _has_matching_pv_tag : _is_same_pv;
-       pvmatch.areas = areas;
-       pvmatch.areas_size = areas_size;
+       pvmatch.areas = alloc_state->areas;
+       pvmatch.areas_size = alloc_state->areas_size;
        pvmatch.pva = pva;
        pvmatch.cling_tag_list_cn = cling_tag_list_cn;
 
+       if (ah->maximise_cling) {
+               /* Check entire LV */
+               le = 0;
+               len = prev_lvseg->le + prev_lvseg->len;
+       } else {
+               /* Only check 1 LE at end of previous LV segment */
+               le = prev_lvseg->le + prev_lvseg->len - 1;
+               len = 1;
+       }
+
        /* FIXME Cope with stacks by flattening */
-       if (!(r = _for_each_pv(cmd, prev_lvseg->lv,
-                              prev_lvseg->le + prev_lvseg->len - 1, 1, NULL, NULL,
+       if (!(r = _for_each_pv(ah->cmd, prev_lvseg->lv, le, len, NULL, NULL,
                               0, 0, -1, 1,
                               _is_condition, &pvmatch)))
                stack;
@@ -1088,14 +1468,14 @@ static int _check_cling(struct cmd_context *cmd,
  */
 static int _check_contiguous(struct cmd_context *cmd,
                             struct lv_segment *prev_lvseg, struct pv_area *pva,
-                            struct pv_area_used *areas, uint32_t areas_size)
+                            struct alloc_state *alloc_state)
 {
        struct pv_match pvmatch;
        int r;
 
        pvmatch.condition = _is_contiguous;
-       pvmatch.areas = areas;
-       pvmatch.areas_size = areas_size;
+       pvmatch.areas = alloc_state->areas;
+       pvmatch.areas_size = alloc_state->areas_size;
        pvmatch.pva = pva;
        pvmatch.cling_tag_list_cn = NULL;
 
@@ -1113,262 +1493,511 @@ static int _check_contiguous(struct cmd_context *cmd,
 }
 
 /*
- * Choose sets of parallel areas to use, respecting any constraints.
+ * Is pva on same PV as any areas already used in this allocation attempt?
+ */
+static int _check_cling_to_alloced(struct alloc_handle *ah, const struct dm_config_node *cling_tag_list_cn,
+                                  struct pv_area *pva, struct alloc_state *alloc_state)
+{
+       unsigned s;
+       struct alloced_area *aa;
+
+       /*
+        * Ignore log areas.  They are always allocated whole as part of the
+        * first allocation.  If they aren't yet set, we know we've nothing to do.
+        */
+       if (alloc_state->log_area_count_still_needed)
+               return 0;
+
+       for (s = 0; s < ah->area_count; s++) {
+               if (alloc_state->areas[s].pva)
+                       continue;       /* Area already assigned */
+               dm_list_iterate_items(aa, &ah->alloced_areas[s]) {
+                       if ((!cling_tag_list_cn && (pva->map->pv == aa[0].pv)) ||
+                           (cling_tag_list_cn && _pvs_have_matching_tag(cling_tag_list_cn, pva->map->pv, aa[0].pv))) {
+                               _reserve_area(&alloc_state->areas[s], pva, pva->count, s + 1, 0);
+                               return 1;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int _pv_is_parallel(struct physical_volume *pv, struct dm_list *parallel_pvs)
+{
+       struct pv_list *pvl;
+
+       dm_list_iterate_items(pvl, parallel_pvs)
+               if (pv == pvl->pv)
+                       return 1;
+
+       return 0;
+}
+
+/*
+ * Decide whether or not to try allocation from supplied area pva.
+ * alloc_state->areas may get modified.
  */
-static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
-                               struct dm_list *pvms, struct pv_area_used **areas_ptr,
-                               uint32_t *areas_size_ptr, unsigned can_split,
-                               struct lv_segment *prev_lvseg,
-                               uint32_t *allocated, uint32_t *log_needs_allocating, uint32_t needed)
+static area_use_t _check_pva(struct alloc_handle *ah, struct pv_area *pva, uint32_t still_needed,
+                            const struct alloc_parms *alloc_parms, struct alloc_state *alloc_state,
+                            unsigned already_found_one, unsigned iteration_count, unsigned log_iteration_count)
+{
+       unsigned s;
+
+       /* Skip fully-reserved areas (which are not currently removed from the list). */
+       if (!pva->unreserved)
+               return NEXT_AREA;
+
+       /* FIXME Should this test be removed? */
+       if (iteration_count)
+               /*
+               * Don't use an area twice.
+               */
+               for (s = 0; s < alloc_state->areas_size; s++)
+                       if (alloc_state->areas[s].pva == pva)
+                               return NEXT_AREA;
+
+       /* If maximise_cling is set, perform several checks, otherwise perform exactly one. */
+       if (!iteration_count && !log_iteration_count && alloc_parms->flags & (A_CONTIGUOUS_TO_LVSEG | A_CLING_TO_LVSEG | A_CLING_TO_ALLOCED)) {
+               /* Contiguous? */
+               if (((alloc_parms->flags & A_CONTIGUOUS_TO_LVSEG) || (ah->maximise_cling && alloc_parms->prev_lvseg)) &&
+                   _check_contiguous(ah->cmd, alloc_parms->prev_lvseg, pva, alloc_state))
+                       return PREFERRED;
+       
+               /* Try next area on same PV if looking for contiguous space */
+               if (alloc_parms->flags & A_CONTIGUOUS_TO_LVSEG)
+                       return NEXT_AREA;
+
+               /* Cling to prev_lvseg? */
+               if (((alloc_parms->flags & A_CLING_TO_LVSEG) || (ah->maximise_cling && alloc_parms->prev_lvseg)) &&
+                   _check_cling(ah, NULL, alloc_parms->prev_lvseg, pva, alloc_state))
+                       /* If this PV is suitable, use this first area */
+                       return PREFERRED;
+
+               /* Cling_to_alloced? */
+               if ((alloc_parms->flags & A_CLING_TO_ALLOCED) &&
+                   _check_cling_to_alloced(ah, NULL, pva, alloc_state))
+                       return PREFERRED;
+
+               /* Cling_by_tags? */
+               if (!(alloc_parms->flags & A_CLING_BY_TAGS) || !ah->cling_tag_list_cn)
+                       return NEXT_PV;
+
+               if (alloc_parms->prev_lvseg) {
+                       if (_check_cling(ah, ah->cling_tag_list_cn, alloc_parms->prev_lvseg, pva, alloc_state))
+                               return PREFERRED;
+               } else if (_check_cling_to_alloced(ah, ah->cling_tag_list_cn, pva, alloc_state))
+                       return PREFERRED;
+
+               /* All areas on this PV give same result so pointless checking more */
+               return NEXT_PV;
+       }
+
+       /* Normal/Anywhere */
+
+       /* Is it big enough on its own? */
+       if (pva->unreserved * ah->area_multiple < still_needed &&
+           ((!(alloc_parms->flags & A_CAN_SPLIT) && !ah->log_area_count) ||
+            (already_found_one && alloc_parms->alloc != ALLOC_ANYWHERE)))
+               return NEXT_PV;
+
+       return USE_AREA;
+}
+
+/*
+ * Decide how many extents we're trying to obtain from a given area.
+ * Removes the extents from further consideration.
+ */
+static uint32_t _calc_required_extents(struct alloc_handle *ah, struct pv_area *pva, unsigned ix_pva, uint32_t max_to_allocate, alloc_policy_t alloc)
+{
+       uint32_t required = max_to_allocate / ah->area_multiple;
+
+       /*
+        * Update amount unreserved - effectively splitting an area 
+        * into two or more parts.  If the whole stripe doesn't fit,
+        * reduce amount we're looking for.
+        */
+       if (alloc == ALLOC_ANYWHERE) {
+               if (ix_pva - 1 >= ah->area_count)
+                       required = ah->log_len;
+       } else if (required < ah->log_len)
+               required = ah->log_len;
+
+       if (required >= pva->unreserved) {
+               required = pva->unreserved;
+               pva->unreserved = 0;
+       } else {
+               pva->unreserved -= required;
+               reinsert_changed_pv_area(pva);
+       }
+
+       return required;
+}
+
+static int _reserve_required_area(struct alloc_handle *ah, uint32_t max_to_allocate,
+                                 unsigned ix_pva, struct pv_area *pva,
+                                 struct alloc_state *alloc_state, alloc_policy_t alloc)
+{
+       uint32_t required = _calc_required_extents(ah, pva, ix_pva, max_to_allocate, alloc);
+       uint32_t s;
+
+       /* Expand areas array if needed after an area was split. */
+       if (ix_pva > alloc_state->areas_size) {
+               alloc_state->areas_size *= 2;
+               if (!(alloc_state->areas = dm_realloc(alloc_state->areas, sizeof(*alloc_state->areas) * (alloc_state->areas_size)))) {
+                       log_error("Memory reallocation for parallel areas failed.");
+                       return 0;
+               }
+               for (s = alloc_state->areas_size / 2; s < alloc_state->areas_size; s++)
+                       alloc_state->areas[s].pva = NULL;
+       }
+
+       _reserve_area(&alloc_state->areas[ix_pva - 1], pva, required, ix_pva, pva->unreserved);
+
+       return 1;
+}
+
+static void _clear_areas(struct alloc_state *alloc_state)
+{
+       uint32_t s;
+
+       for (s = 0; s < alloc_state->areas_size; s++)
+               alloc_state->areas[s].pva = NULL;
+}
+
+static void _reset_unreserved(struct dm_list *pvms)
 {
        struct pv_map *pvm;
        struct pv_area *pva;
-       struct pv_list *pvl;
-       unsigned already_found_one = 0;
-       unsigned contiguous = 0, cling = 0, use_cling_tags = 0, preferred_count = 0;
-       unsigned ix, last_ix;
+
+       dm_list_iterate_items(pvm, pvms)
+               dm_list_iterate_items(pva, &pvm->areas)
+                       if (pva->unreserved != pva->count) {
+                               pva->unreserved = pva->count;
+                               reinsert_changed_pv_area(pva);
+                       }
+}
+
+static void _report_needed_allocation_space(struct alloc_handle *ah,
+                                           struct alloc_state *alloc_state)
+{
+       const char *metadata_type;
+       uint32_t parallel_areas_count, parallel_area_size;
+       uint32_t metadata_count, metadata_size;
+
+       parallel_area_size = (ah->new_extents - alloc_state->allocated) / ah->area_multiple -
+                     ((ah->alloc_and_split_meta) ? ah->log_len : 0);
+
+       parallel_areas_count = ah->area_count + ah->parity_count;
+
+       metadata_size = ah->log_len;
+       if (ah->alloc_and_split_meta) {
+               metadata_type = "RAID metadata area";
+               metadata_count = parallel_areas_count;
+       } else {
+               metadata_type = "mirror log";
+               metadata_count = alloc_state->log_area_count_still_needed;
+       }
+
+       log_debug("Still need %" PRIu32 " total extents:",
+               parallel_area_size * parallel_areas_count + metadata_size * metadata_count);
+       log_debug("  %" PRIu32 " (%" PRIu32 " data/%" PRIu32
+                 " parity) parallel areas of %" PRIu32 " extents each",
+                 parallel_areas_count, ah->area_count, ah->parity_count, parallel_area_size);
+       log_debug("  %" PRIu32 " %ss of %" PRIu32 " extents each",
+                 metadata_count, metadata_type, metadata_size);
+}
+/*
+ * Returns 1 regardless of whether any space was found, except on error.
+ */
+static int _find_some_parallel_space(struct alloc_handle *ah, const struct alloc_parms *alloc_parms,
+                                    struct dm_list *pvms, struct alloc_state *alloc_state,
+                                    struct dm_list *parallel_pvs, uint32_t max_to_allocate)
+{
+       unsigned ix = 0;
+       unsigned last_ix;
+       struct pv_map *pvm;
+       struct pv_area *pva;
+       unsigned preferred_count = 0;
+       unsigned already_found_one;
        unsigned ix_offset = 0; /* Offset for non-preferred allocations */
        unsigned ix_log_offset; /* Offset to start of areas to use for log */
        unsigned too_small_for_log_count; /* How many too small for log? */
-       uint32_t max_parallel;  /* Maximum extents to allocate */
-       uint32_t next_le;
-       uint32_t required;      /* Extents we're trying to obtain from a given area */
-       struct seg_pvs *spvs;
-       struct dm_list *parallel_pvs;
-       uint32_t free_pes;
+       unsigned iteration_count = 0; /* cling_to_alloced may need 2 iterations */
+       unsigned log_iteration_count = 0; /* extra iteration for logs on data devices */
        struct alloced_area *aa;
        uint32_t s;
-       uint32_t total_extents_needed = (needed - *allocated) * ah->area_count / ah->area_multiple;
+       uint32_t devices_needed = ah->area_count + ah->parity_count;
 
-       /* Is there enough total space? */
-       free_pes = pv_maps_size(pvms);
-       if (total_extents_needed > free_pes) {
-               log_error("Insufficient free space: %" PRIu32 " extents needed,"
-                         " but only %" PRIu32 " available",
-                         total_extents_needed, free_pes);
-               return 0;
-       }
+       /* ix_offset holds the number of parallel allocations that must be contiguous/cling */
+       /* At most one of A_CONTIGUOUS_TO_LVSEG, A_CLING_TO_LVSEG or A_CLING_TO_ALLOCED may be set */
+       if (alloc_parms->flags & (A_CONTIGUOUS_TO_LVSEG | A_CLING_TO_LVSEG))
+               ix_offset = _stripes_per_mimage(alloc_parms->prev_lvseg) * alloc_parms->prev_lvseg->area_count;
 
-       /* FIXME Select log PV appropriately if there isn't one yet */
+       if (alloc_parms->flags & A_CLING_TO_ALLOCED)
+               ix_offset = ah->area_count;
 
-       /* Are there any preceding segments we must follow on from? */
-       if (prev_lvseg) {
-               ix_offset = _stripes_per_mimage(prev_lvseg) * prev_lvseg->area_count;
-               if ((alloc == ALLOC_CONTIGUOUS))
-                       contiguous = 1;
-               else if ((alloc == ALLOC_CLING))
-                       cling = 1;
-               else if ((alloc == ALLOC_CLING_BY_TAGS)) {
-                       cling = 1;
-                       use_cling_tags = 1;
-               } else
-                       ix_offset = 0;
-       }
+       if (alloc_parms->alloc == ALLOC_NORMAL || (alloc_parms->flags & A_CLING_TO_ALLOCED))
+               log_debug("Cling_to_allocated is %sset",
+                         alloc_parms->flags & A_CLING_TO_ALLOCED ? "" : "not ");
+
+       _clear_areas(alloc_state);
+       _reset_unreserved(pvms);
+
+       _report_needed_allocation_space(ah, alloc_state);
 
-       /* FIXME This algorithm needs a lot of cleaning up! */
-       /* FIXME anywhere doesn't find all space yet */
-       /* ix_offset holds the number of allocations that must be contiguous */
        /* ix holds the number of areas found on other PVs */
        do {
-               ix = 0;
-               preferred_count = 0;
-
-               parallel_pvs = NULL;
-               max_parallel = needed;
+               if (log_iteration_count) {
+                       log_debug("Found %u areas for %" PRIu32 " parallel areas and %" PRIu32 " log areas so far.", ix, devices_needed, alloc_state->log_area_count_still_needed);
+               } else if (iteration_count)
+                       log_debug("Filled %u out of %u preferred areas so far.", preferred_count, ix_offset);
 
                /*
-                * If there are existing parallel PVs, avoid them and reduce
-                * the maximum we can allocate in one go accordingly.
+                * Provide for escape from the loop if no progress is made.
+                * This should not happen: ALLOC_ANYWHERE should be able to use
+                * all available space. (If there aren't enough extents, the code
+                * should not reach this point.)
                 */
-               if (ah->parallel_areas) {
-                       next_le = (prev_lvseg ? prev_lvseg->le + prev_lvseg->len : 0) + *allocated / ah->area_multiple;
-                       dm_list_iterate_items(spvs, ah->parallel_areas) {
-                               if (next_le >= spvs->le + spvs->len)
-                                       continue;
+               last_ix = ix;
 
-                               if (max_parallel > (spvs->le + spvs->len) * ah->area_multiple)
-                                       max_parallel = (spvs->le + spvs->len) * ah->area_multiple;
-                               parallel_pvs = &spvs->pvs;
-                               break;
-                       }
-               }
-
-               do {
-                       /*
-                        * Provide for escape from the loop if no progress is made.
-                        * This should not happen: ALLOC_ANYWHERE should be able to use
-                        * all available space. (If there aren't enough extents, the code
-                        * should not reach this point.)
-                        */
-                       last_ix = ix;
-
-                       /*
-                        * Put the smallest area of each PV that is at least the
-                        * size we need into areas array.  If there isn't one
-                        * that fits completely and we're allowed more than one
-                        * LV segment, then take the largest remaining instead.
-                        */
-                       dm_list_iterate_items(pvm, pvms) {
-                               if (dm_list_empty(&pvm->areas))
-                                       continue;       /* Next PV */
-
-                               if (alloc != ALLOC_ANYWHERE) {
-                                       /* Don't allocate onto the log pv */
-                                       if (ah->log_area_count)
-                                               dm_list_iterate_items(aa, &ah->alloced_areas[ah->area_count])
-                                                       for (s = 0; s < ah->log_area_count; s++)
-                                                               if (!aa[s].pv)
-                                                                       goto next_pv;
-
-                                       /* Avoid PVs used by existing parallel areas */
-                                       if (parallel_pvs)
-                                               dm_list_iterate_items(pvl, parallel_pvs)
-                                                       if (pvm->pv == pvl->pv)
+               /*
+                * Put the smallest area of each PV that is at least the
+                * size we need into areas array.  If there isn't one
+                * that fits completely and we're allowed more than one
+                * LV segment, then take the largest remaining instead.
+                */
+               dm_list_iterate_items(pvm, pvms) {
+                       /* PV-level checks */
+                       if (dm_list_empty(&pvm->areas))
+                               continue;       /* Next PV */
+
+                       if (alloc_parms->alloc != ALLOC_ANYWHERE) {
+                               /* Don't allocate onto the log PVs */
+                               if (ah->log_area_count)
+                                       dm_list_iterate_items(aa, &ah->alloced_areas[ah->area_count])
+                                               for (s = 0; s < ah->log_area_count; s++)
+                                                       if (!aa[s].pv)
                                                                goto next_pv;
-                               }
 
-                               already_found_one = 0;
-                               /* First area in each list is the largest */
-                               dm_list_iterate_items(pva, &pvm->areas) {
-                                       /* Skip fully-reserved areas (which are not currently removed from the list). */
-                                       if (!pva->unreserved)
-                                               continue;
-                                       if (contiguous) {
-                                               if (prev_lvseg &&
-                                                   _check_contiguous(ah->cmd,
-                                                                     prev_lvseg,
-                                                                     pva, *areas_ptr,
-                                                                     *areas_size_ptr)) {
-                                                       preferred_count++;
+                               /* FIXME Split into log and non-log parallel_pvs and only check the log ones if log_iteration? */
+                               /* (I've temporatily disabled the check.) */
+                               /* Avoid PVs used by existing parallel areas */
+                               if (!log_iteration_count && parallel_pvs && _pv_is_parallel(pvm->pv, parallel_pvs))
+                                       goto next_pv;
+
+                               /*
+                                * Avoid PVs already set aside for log.  
+                                * We only reach here if there were enough PVs for the main areas but
+                                * not enough for the logs.
+                                */
+                               if (log_iteration_count) {
+                                       for (s = devices_needed; s < ix + ix_offset; s++)
+                                               if (alloc_state->areas[s].pva && alloc_state->areas[s].pva->map->pv == pvm->pv)
                                                        goto next_pv;
-                                               }
-                                               continue;
-                                       }
-
-                                       if (cling) {
-                                               if (prev_lvseg &&
-                                                   _check_cling(ah->cmd,
-                                                                use_cling_tags ? ah->cling_tag_list_cn : NULL,
-                                                                prev_lvseg,
-                                                                pva, *areas_ptr,
-                                                                *areas_size_ptr)) {
-                                                       preferred_count++;
-                                               }
-                                               goto next_pv;
-                                       }
+                               /* On a second pass, avoid PVs already used in an uncommitted area */
+                               } else if (iteration_count)
+                                       for (s = 0; s < devices_needed; s++)
+                                               if (alloc_state->areas[s].pva && alloc_state->areas[s].pva->map->pv == pvm->pv)
+                                                       goto next_pv;
+                       }
 
-                                       /* Is it big enough on its own? */
-                                       if (pva->unreserved * ah->area_multiple <
-                                           max_parallel - *allocated &&
-                                           ((!can_split && !ah->log_area_count) ||
-                                            (already_found_one &&
-                                             !(alloc == ALLOC_ANYWHERE))))
-                                               goto next_pv;
+                       already_found_one = 0;
+                       /* First area in each list is the largest */
+                       dm_list_iterate_items(pva, &pvm->areas) {
+                               /*
+                                * There are two types of allocations, which can't be mixed at present.
+                                * PREFERRED are stored immediately in a specific parallel slot.
+                                * USE_AREA are stored for later, then sorted and chosen from.
+                                */
+                               switch(_check_pva(ah, pva, max_to_allocate, alloc_parms,
+                                                 alloc_state, already_found_one, iteration_count, log_iteration_count)) {
+
+                               case PREFERRED:
+                                       preferred_count++;
+                                       /* Fall through */
+
+                               case NEXT_PV:
+                                       goto next_pv;
+
+                               case NEXT_AREA:
+                                       continue;
 
+                               case USE_AREA:
                                        /*
                                         * Except with ALLOC_ANYWHERE, replace first area with this
                                         * one which is smaller but still big enough.
                                         */
                                        if (!already_found_one ||
-                                           alloc == ALLOC_ANYWHERE) {
+                                           alloc_parms->alloc == ALLOC_ANYWHERE) {
                                                ix++;
                                                already_found_one = 1;
                                        }
 
-                                       required = (max_parallel - *allocated) / ah->area_multiple;
-
-                                       if (alloc == ALLOC_ANYWHERE) {
-                                               /*
-                                                * Update amount unreserved - effectively splitting an area 
-                                                * into two or more parts.  If the whole stripe doesn't fit,
-                                                * reduce amount we're looking for.
-                                                */
-                                               if (ix + ix_offset - 1 >= ah->area_count)
-                                                       required = ah->log_len;
-                                               if (required >= pva->unreserved) {
-                                                       required = pva->unreserved;
-                                                       pva->unreserved = 0;
-                                               } else {
-                                                       pva->unreserved -= required;
-                                                       reinsert_reduced_pv_area(pva);
-                                               }
-                                       } else {
-                                               if (required < ah->log_len)
-                                                       required = ah->log_len;
-                                               if (required > pva->count)
-                                                       required = pva->count;
-                                       }
-
-                                       /* Expand areas array if needed after an area was split. */
-                                       if (ix + ix_offset > *areas_size_ptr) {
-                                               *areas_size_ptr *= 2;
-                                               if (!(*areas_ptr = dm_realloc(*areas_ptr,
-                                                                            sizeof(**areas_ptr) *
-                                                                            (*areas_size_ptr)))) {
-                                                       log_error("Memory reallocation for parallel areas failed.");
-                                                       return 0;
-                                               }
-                                       }
-                                       (*areas_ptr)[ix + ix_offset - 1].pva = pva;
-                                               (*areas_ptr)[ix + ix_offset - 1].used = required;
-                                       log_debug("Trying allocation area %" PRIu32 " on %s start PE %" PRIu32
-                                                 " length %" PRIu32 " leaving %" PRIu32 ".",
-                                                 ix + ix_offset - 1, dev_name(pva->map->pv->dev), pva->start, required,
-                                                 (alloc == ALLOC_ANYWHERE) ? pva->unreserved : pva->count - required);
+                                       /* Reserve required amount of pva */
+                                       if (!_reserve_required_area(ah, max_to_allocate, ix + ix_offset,
+                                                                   pva, alloc_state, alloc_parms->alloc))
+                                               return_0;
                                }
-                       next_pv:
-                               /* With ALLOC_ANYWHERE we ignore further PVs once we have at least enough areas */
-                               /* With cling and contiguous we stop if we found a match for *all* the areas */
-                               /* FIXME Rename these variables! */
-                               if ((alloc == ALLOC_ANYWHERE &&
-                                   ix + ix_offset >= ah->area_count + (*log_needs_allocating ? ah->log_area_count : 0)) ||
-                                   (preferred_count == ix_offset &&
-                                    (ix_offset == ah->area_count + (*log_needs_allocating ? ah->log_area_count : 0))))
-                                       break;
+
                        }
-               } while (alloc == ALLOC_ANYWHERE && last_ix != ix && ix < ah->area_count + (*log_needs_allocating ? ah->log_area_count : 0));
 
-               if (preferred_count < ix_offset)
-                       break;
+               next_pv:
+                       /* With ALLOC_ANYWHERE we ignore further PVs once we have at least enough areas */
+                       /* With cling and contiguous we stop if we found a match for *all* the areas */
+                       /* FIXME Rename these variables! */
+                       if ((alloc_parms->alloc == ALLOC_ANYWHERE &&
+                           ix + ix_offset >= devices_needed + alloc_state->log_area_count_still_needed) ||
+                           (preferred_count == ix_offset &&
+                            (ix_offset == devices_needed + alloc_state->log_area_count_still_needed)))
+                               break;
+               }
+       } while ((alloc_parms->alloc == ALLOC_ANYWHERE && last_ix != ix && ix < devices_needed + alloc_state->log_area_count_still_needed) ||
+               /* With cling_to_alloced and normal, if there were gaps in the preferred areas, have a second iteration */
+                (alloc_parms->alloc == ALLOC_NORMAL && preferred_count &&
+                 (preferred_count < ix_offset || alloc_state->log_area_count_still_needed) &&
+                 (alloc_parms->flags & A_CLING_TO_ALLOCED) && !iteration_count++) ||
+               /* Extra iteration needed to fill log areas on PVs already used? */
+                (alloc_parms->alloc == ALLOC_NORMAL && preferred_count == ix_offset && !ah->mirror_logs_separate &&
+                 (ix + preferred_count >= devices_needed) &&
+                 (ix + preferred_count < devices_needed + alloc_state->log_area_count_still_needed) && !log_iteration_count++));
+
+       if (preferred_count < ix_offset && !(alloc_parms->flags & A_CLING_TO_ALLOCED))
+               return 1;
 
-               if (ix + ix_offset < ah->area_count +
-                  (*log_needs_allocating ? ah->log_area_count : 0))
-                       break;
+       if (ix + preferred_count < devices_needed + alloc_state->log_area_count_still_needed)
+               return 1;
 
-               /* Sort the areas so we allocate from the biggest */
-               if (ix > 1)
-                       qsort((*areas_ptr) + ix_offset, ix, sizeof(**areas_ptr),
+       /* Sort the areas so we allocate from the biggest */
+       if (log_iteration_count) {
+               if (ix > devices_needed + 1) {
+                       log_debug("Sorting %u log areas", ix - devices_needed);
+                       qsort(alloc_state->areas + devices_needed, ix - devices_needed, sizeof(*alloc_state->areas),
                              _comp_area);
+               }
+       } else if (ix > 1) {
+               log_debug("Sorting %u areas", ix);
+               qsort(alloc_state->areas + ix_offset, ix, sizeof(*alloc_state->areas),
+                     _comp_area);
+       }
+
+       /* If there are gaps in our preferred areas, fill then from the sorted part of the array */
+       if (preferred_count && preferred_count != ix_offset) {
+               for (s = 0; s < devices_needed; s++)
+                       if (!alloc_state->areas[s].pva) {
+                               alloc_state->areas[s].pva = alloc_state->areas[ix_offset].pva;
+                               alloc_state->areas[s].used = alloc_state->areas[ix_offset].used;
+                               alloc_state->areas[ix_offset++].pva = NULL;
+                       }
+       }
+       
+       /*
+        * First time around, if there's a log, allocate it on the
+        * smallest device that has space for it.
+        */
+       too_small_for_log_count = 0;
+       ix_log_offset = 0;
+
+       /* FIXME This logic is due to its heritage and can be simplified! */
+       if (alloc_state->log_area_count_still_needed) {
+               /* How many areas are too small for the log? */
+               while (too_small_for_log_count < ix_offset + ix &&
+                      (*(alloc_state->areas + ix_offset + ix - 1 -
+                         too_small_for_log_count)).used < ah->log_len)
+                       too_small_for_log_count++;
+               ix_log_offset = ix_offset + ix - too_small_for_log_count - ah->log_area_count;
+       }
+
+       if (ix + ix_offset < devices_needed +
+           (alloc_state->log_area_count_still_needed ? alloc_state->log_area_count_still_needed +
+                                   too_small_for_log_count : 0))
+               return 1;
+
+       /*
+        * Finally add the space identified to the list of areas to be used.
+        */
+       if (!_alloc_parallel_area(ah, max_to_allocate, alloc_state, ix_log_offset))
+               return_0;
+
+       /*
+        * Log is always allocated first time.
+        */
+       alloc_state->log_area_count_still_needed = 0;
+
+       return 1;
+}
+
+/*
+ * Choose sets of parallel areas to use, respecting any constraints 
+ * supplied in alloc_parms.
+ */
+static int _find_max_parallel_space_for_one_policy(struct alloc_handle *ah, struct alloc_parms *alloc_parms,
+                                                  struct dm_list *pvms, struct alloc_state *alloc_state)
+{
+       uint32_t max_tmp;
+       uint32_t max_to_allocate;       /* Maximum extents to allocate this time */
+       uint32_t old_allocated;
+       uint32_t next_le;
+       struct seg_pvs *spvs;
+       struct dm_list *parallel_pvs;
+
+       /* FIXME This algorithm needs a lot of cleaning up! */
+       /* FIXME anywhere doesn't find all space yet */
+       do {
+               parallel_pvs = NULL;
+               max_to_allocate = alloc_parms->extents_still_needed - alloc_state->allocated;
 
                /*
-                * First time around, if there's a log, allocate it on the
-                * smallest device that has space for it.
+                * If there are existing parallel PVs, avoid them and reduce
+                * the maximum we can allocate in one go accordingly.
                 */
-               too_small_for_log_count = 0;
-               ix_log_offset = 0;
-
-               /* FIXME This logic is due to its heritage and can be simplified! */
-               if (*log_needs_allocating) {
-                       /* How many areas are too small for the log? */
-                       while (too_small_for_log_count < ix_offset + ix &&
-                              (*((*areas_ptr) + ix_offset + ix - 1 -
-                                 too_small_for_log_count)).used < ah->log_len)
-                               too_small_for_log_count++;
-                       ix_log_offset = ix_offset + ix - too_small_for_log_count - ah->log_area_count;
-               }
-
-               if (ix + ix_offset < ah->area_count +
-                   (*log_needs_allocating ? ah->log_area_count +
-                                           too_small_for_log_count : 0))
-                       break;
+               if (ah->parallel_areas) {
+                       next_le = (alloc_parms->prev_lvseg ? alloc_parms->prev_lvseg->le + alloc_parms->prev_lvseg->len : 0) + alloc_state->allocated / ah->area_multiple;
+                       dm_list_iterate_items(spvs, ah->parallel_areas) {
+                               if (next_le >= spvs->le + spvs->len)
+                                       continue;
 
-               if (!_alloc_parallel_area(ah, max_parallel, *areas_ptr, allocated,
-                                         *log_needs_allocating, ix_log_offset))
-                       return_0;
+                               max_tmp = max_to_allocate +
+                                       alloc_state->allocated;
+
+                               /*
+                                * Because a request that groups metadata and
+                                * data together will be split, we must adjust
+                                * the comparison accordingly.
+                                */
+                               if (ah->alloc_and_split_meta)
+                                       max_tmp -= ah->log_len;
+                               if (max_tmp > (spvs->le + spvs->len) * ah->area_multiple) {
+                                       max_to_allocate = (spvs->le + spvs->len) * ah->area_multiple - alloc_state->allocated;
+                                       max_to_allocate += ah->alloc_and_split_meta ? ah->log_len : 0;
+                               }
+                               parallel_pvs = &spvs->pvs;
+                               break;
+                       }
+               }
 
-               *log_needs_allocating = 0;
+               old_allocated = alloc_state->allocated;
+
+               if (!_find_some_parallel_space(ah, alloc_parms, pvms, alloc_state, parallel_pvs, max_to_allocate))
+                       return_0;
 
-       } while ((alloc != ALLOC_CONTIGUOUS) && *allocated != needed && can_split);
+               /*
+                * If we didn't allocate anything this time with ALLOC_NORMAL and had
+                * A_CLING_TO_ALLOCED set, try again without it.
+                *
+                * For ALLOC_NORMAL, if we did allocate something without the
+                * flag set, set it and continue so that further allocations
+                * remain on the same disks where possible.
+                */
+               if (old_allocated == alloc_state->allocated) {
+                       if ((alloc_parms->alloc == ALLOC_NORMAL) && (alloc_parms->flags & A_CLING_TO_ALLOCED))
+                               alloc_parms->flags &= ~A_CLING_TO_ALLOCED;
+                       else
+                               break;  /* Give up */
+               } else if (ah->maximise_cling && alloc_parms->alloc == ALLOC_NORMAL &&
+                          !(alloc_parms->flags & A_CLING_TO_ALLOCED))
+                       alloc_parms->flags |= A_CLING_TO_ALLOCED;
+       } while ((alloc_parms->alloc != ALLOC_CONTIGUOUS) && alloc_state->allocated != alloc_parms->extents_still_needed && (alloc_parms->flags & A_CAN_SPLIT));
 
        return 1;
 }
@@ -1384,23 +2013,30 @@ static int _allocate(struct alloc_handle *ah,
                     unsigned can_split,
                     struct dm_list *allocatable_pvs)
 {
-       struct pv_area_used *areas;
-       uint32_t allocated = lv ? lv->le_count : 0;
        uint32_t old_allocated;
        struct lv_segment *prev_lvseg = NULL;
        int r = 0;
        struct dm_list *pvms;
-       uint32_t areas_size;
        alloc_policy_t alloc;
-       unsigned log_needs_allocating = 0;
+       struct alloc_parms alloc_parms;
+       struct alloc_state alloc_state;
 
-       if (allocated >= ah->new_extents && !ah->log_area_count) {
+       alloc_state.allocated = lv ? lv->le_count : 0;
+
+       if (alloc_state.allocated >= ah->new_extents && !ah->log_area_count) {
                log_error("_allocate called with no work to do!");
                return 1;
        }
 
-       if (ah->log_area_count)
-               log_needs_allocating = 1;
+        if (ah->area_multiple > 1 &&
+            (ah->new_extents - alloc_state.allocated) % ah->area_multiple) {
+               log_error("Number of extents requested (%d) needs to be divisible by %d.",
+                         ah->new_extents - alloc_state.allocated,
+                         ah->area_multiple);
+               return 0;
+       }
+
+       alloc_state.log_area_count_still_needed = ah->log_area_count;
 
        if (ah->alloc == ALLOC_CONTIGUOUS)
                can_split = 0;
@@ -1417,24 +2053,25 @@ static int _allocate(struct alloc_handle *ah,
        if (!_log_parallel_areas(ah->mem, ah->parallel_areas))
                stack;
 
-       areas_size = dm_list_size(pvms);
-       if (areas_size && areas_size < (ah->area_count + ah->log_area_count)) {
-               if (ah->alloc != ALLOC_ANYWHERE) {
+       alloc_state.areas_size = dm_list_size(pvms);
+       if (alloc_state.areas_size &&
+           alloc_state.areas_size < (ah->area_count + ah->parity_count + ah->log_area_count)) {
+               if (ah->alloc != ALLOC_ANYWHERE && ah->mirror_logs_separate) {
                        log_error("Not enough PVs with free space available "
                                  "for parallel allocation.");
                        log_error("Consider --alloc anywhere if desperate.");
                        return 0;
                }
-               areas_size = ah->area_count + ah->log_area_count;
+               alloc_state.areas_size = ah->area_count + ah->parity_count + ah->log_area_count;
        }
 
        /* Upper bound if none of the PVs in prev_lvseg is in pvms */
        /* FIXME Work size out properly */
        if (prev_lvseg)
-               areas_size += _stripes_per_mimage(prev_lvseg) * prev_lvseg->area_count;
+               alloc_state.areas_size += _stripes_per_mimage(prev_lvseg) * prev_lvseg->area_count;
 
        /* Allocate an array of pv_areas to hold the largest space on each PV */
-       if (!(areas = dm_malloc(sizeof(*areas) * areas_size))) {
+       if (!(alloc_state.areas = dm_malloc(sizeof(*alloc_state.areas) * alloc_state.areas_size))) {
                log_error("Couldn't allocate areas array.");
                return 0;
        }
@@ -1447,41 +2084,40 @@ static int _allocate(struct alloc_handle *ah,
                ah->alloc = ALLOC_CLING_BY_TAGS;
 
        /* Attempt each defined allocation policy in turn */
-       for (alloc = ALLOC_CONTIGUOUS; alloc < ALLOC_INHERIT; alloc++) {
+       for (alloc = ALLOC_CONTIGUOUS; alloc <= ah->alloc; alloc++) {
                /* Skip cling_by_tags if no list defined */
                if (alloc == ALLOC_CLING_BY_TAGS && !ah->cling_tag_list_cn)
                        continue;
-               old_allocated = allocated;
-               log_debug("Trying allocation using %s policy.  "
-                         "Need %" PRIu32 " extents for %" PRIu32 " parallel areas and %" PRIu32 " log areas of %" PRIu32 " extents. "
-                         "(Total %" PRIu32 " extents.)",
-                         get_alloc_string(alloc),
-                         (ah->new_extents - allocated) / ah->area_multiple,
-                         ah->area_count, log_needs_allocating ? ah->log_area_count : 0,
-                         log_needs_allocating ? ah->log_len : 0,
-                         (ah->new_extents - allocated) * ah->area_count / ah->area_multiple +
-                               (log_needs_allocating ? ah->log_area_count * ah->log_len : 0));
-               if (!_find_parallel_space(ah, alloc, pvms, &areas,
-                                         &areas_size, can_split,
-                                         prev_lvseg, &allocated, &log_needs_allocating, ah->new_extents))
+               old_allocated = alloc_state.allocated;
+               log_debug("Trying allocation using %s policy.", get_alloc_string(alloc));
+
+               if (!_sufficient_pes_free(ah, pvms, alloc_state.allocated, ah->new_extents))
+                       goto_out;
+
+               _init_alloc_parms(ah, &alloc_parms, alloc, prev_lvseg,
+                                 can_split, alloc_state.allocated,
+                                 ah->new_extents);
+
+               if (!_find_max_parallel_space_for_one_policy(ah, &alloc_parms, pvms, &alloc_state))
                        goto_out;
-               if ((allocated == ah->new_extents && !log_needs_allocating) || (ah->alloc == alloc) ||
-                   (!can_split && (allocated != old_allocated)))
+
+               if ((alloc_state.allocated == ah->new_extents && !alloc_state.log_area_count_still_needed) ||
+                   (!can_split && (alloc_state.allocated != old_allocated)))
                        break;
        }
 
-       if (allocated != ah->new_extents) {
+       if (alloc_state.allocated != ah->new_extents) {
                log_error("Insufficient suitable %sallocatable extents "
                          "for logical volume %s: %u more required",
                          can_split ? "" : "contiguous ",
                          lv ? lv->name : "",
-                         (ah->new_extents - allocated) * ah->area_count
+                         (ah->new_extents - alloc_state.allocated) * ah->area_count
                          / ah->area_multiple);
                goto out;
        }
 
-       if (log_needs_allocating) {
-               log_error("Insufficient extents for log allocation "
+       if (alloc_state.log_area_count_still_needed) {
+               log_error("Insufficient free space for log allocation "
                          "for logical volume %s.",
                          lv ? lv->name : "");
                goto out;
@@ -1490,29 +2126,57 @@ static int _allocate(struct alloc_handle *ah,
        r = 1;
 
       out:
-       dm_free(areas);
+       dm_free(alloc_state.areas);
        return r;
 }
 
 int lv_add_virtual_segment(struct logical_volume *lv, uint64_t status,
-                          uint32_t extents, const struct segment_type *segtype)
+                          uint32_t extents, const struct segment_type *segtype,
+                          const char *thin_pool_name)
 {
        struct lv_segment *seg;
+       struct logical_volume *thin_pool_lv = NULL;
+       struct lv_list *lvl;
+       uint32_t size;
 
-       if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv,
-                                    lv->le_count, extents, status, 0,
-                                    NULL, 0, extents, 0, 0, 0, NULL))) {
-               log_error("Couldn't allocate new zero segment.");
-               return 0;
+       if (thin_pool_name) {
+               if (!(lvl = find_lv_in_vg(lv->vg, thin_pool_name))) {
+                       log_error("Unable to find existing pool LV %s in VG %s.",
+                                 thin_pool_name, lv->vg->name);
+                       return 0;
+               }
+               thin_pool_lv = lvl->lv;
+               size = first_seg(thin_pool_lv)->chunk_size;
+               if (lv->vg->extent_size < size) {
+                       /* Align extents on chunk boundary size */
+                       size = ((uint64_t)lv->vg->extent_size * extents + size - 1) /
+                               size * size / lv->vg->extent_size;
+                       if (size != extents) {
+                               log_print_unless_silent("Rounding size (%d extents) up to chunk boundary "
+                                                       "size (%d extents).", extents, size);
+                               extents = size;
+                       }
+               }
        }
 
-       dm_list_add(&lv->segments, &seg->list);
+       if (!dm_list_empty(&lv->segments) &&
+           (seg = last_seg(lv)) && (seg->segtype == segtype)) {
+               seg->area_len += extents;
+               seg->len += extents;
+       } else {
+               if (!(seg = alloc_lv_segment(segtype, lv, lv->le_count, extents,
+                                            status, 0, NULL, thin_pool_lv, 0,
+                                            extents, 0, 0, 0, NULL))) {
+                       log_error("Couldn't allocate new zero segment.");
+                       return 0;
+               }
+               lv->status |= VIRTUAL;
+               dm_list_add(&lv->segments, &seg->list);
+       }
 
        lv->le_count += extents;
        lv->size += (uint64_t) extents *lv->vg->extent_size;
 
-       lv->status |= VIRTUAL;
-
        return 1;
 }
 
@@ -1537,6 +2201,11 @@ struct alloc_handle *allocate_extents(struct volume_group *vg,
                return NULL;
        }
 
+       if (!allocatable_pvs) {
+               log_error(INTERNAL_ERROR "Missing allocatable pvs.");
+               return NULL;
+       }
+
        if (vg->fid->fmt->ops->segtype_supported &&
            !vg->fid->fmt->ops->segtype_supported(vg->fid, segtype)) {
                log_error("Metadata format (%s) does not support required "
@@ -1547,7 +2216,7 @@ struct alloc_handle *allocate_extents(struct volume_group *vg,
                return NULL;
        }
 
-       if (alloc == ALLOC_INHERIT)
+       if (alloc >= ALLOC_INHERIT)
                alloc = vg->alloc;
 
        new_extents = (lv ? lv->le_count : 0) + extents;
@@ -1557,8 +2226,7 @@ struct alloc_handle *allocate_extents(struct volume_group *vg,
                               parallel_areas)))
                return_NULL;
 
-       if (!segtype_is_virtual(segtype) &&
-           !_allocate(ah, vg, lv, 1, allocatable_pvs)) {
+       if (!_allocate(ah, vg, lv, 1, allocatable_pvs)) {
                alloc_destroy(ah);
                return_NULL;
        }
@@ -1634,11 +2302,10 @@ static struct lv_segment *_convert_seg_to_mirror(struct lv_segment *seg,
                return NULL;
        }
 
-       if (!(newseg = alloc_lv_segment(seg->lv->vg->cmd->mem,
-                                       get_segtype_from_string(seg->lv->vg->cmd, "mirror"),
+       if (!(newseg = alloc_lv_segment(get_segtype_from_string(seg->lv->vg->cmd, "mirror"),
                                        seg->lv, seg->le, seg->len,
                                        seg->status, seg->stripe_size,
-                                       log_lv,
+                                       log_lv, NULL,
                                        seg->area_count, seg->area_len,
                                        seg->chunk_size, region_size,
                                        seg->extents_copied, NULL))) {
@@ -1731,7 +2398,7 @@ int lv_add_mirror_lvs(struct logical_volume *lv,
 
        if (dm_list_size(&lv->segments) != 1 || seg_type(seg, 0) != AREA_LV) {
                log_error("Mirror layer must be inserted before adding mirrors");
-               return_0;
+               return 0;
        }
 
        mirror_segtype = get_segtype_from_string(lv->vg->cmd, "mirror");
@@ -1781,7 +2448,7 @@ int lv_add_mirror_lvs(struct logical_volume *lv,
  * If we used AREA_PVs under the mirror layer of a log, we could
  * assemble it all at once by calling 'lv_add_segment' with the
  * appropriate segtype (mirror/stripe), like this:
- *     lv_add_segment(ah, ah->area_count, ah->log_area_count,
+ *     lv_add_segment(ah, ah->area_count, ah->log_area_count,
  *                    log_lv, segtype, 0, MIRROR_LOG, 0);
  *
  * For now, we use the same mechanism to build a mirrored log as we
@@ -1798,37 +2465,212 @@ int lv_add_log_segment(struct alloc_handle *ah, uint32_t first_area,
                              0, status, 0);
 }
 
-static int _lv_extend_mirror(struct alloc_handle *ah,
-                            struct logical_volume *lv,
-                            uint32_t extents, uint32_t first_area,
-                            uint32_t stripes, uint32_t stripe_size)
+static int _lv_insert_empty_sublvs(struct logical_volume *lv,
+                                  const struct segment_type *segtype,
+                                  uint32_t stripe_size, uint32_t region_size,
+                                  uint32_t devices)
+{
+       struct logical_volume *sub_lv;
+       uint32_t i;
+       uint64_t sub_lv_status = 0;
+       const char *layer_name;
+       size_t len = strlen(lv->name) + 32;
+       char img_name[len];
+       struct lv_segment *mapseg;
+
+       if (lv->le_count || !dm_list_empty(&lv->segments)) {
+               log_error(INTERNAL_ERROR
+                         "Non-empty LV passed to _lv_insert_empty_sublv");
+               return 0;
+       }
+
+       if (segtype_is_raid(segtype)) {
+               lv->status |= RAID;
+               sub_lv_status = RAID_IMAGE;
+               layer_name = "rimage";
+       } else if (segtype_is_mirrored(segtype)) {
+               lv->status |= MIRRORED;
+               sub_lv_status = MIRROR_IMAGE;
+               layer_name = "mimage";
+       } else
+               return_0;
+
+       /*
+        * First, create our top-level segment for our top-level LV
+        */
+       if (!(mapseg = alloc_lv_segment(segtype, lv, 0, 0, lv->status,
+                                       stripe_size, NULL, NULL,
+                                       devices, 0, 0, region_size, 0, NULL))) {
+               log_error("Failed to create mapping segment for %s", lv->name);
+               return 0;
+       }
+
+       /*
+        * Next, create all of our sub_lv's and link them in.
+        */
+       for (i = 0; i < devices; i++) {
+               /* Data LVs */
+               if (devices > 1) {
+                       if (dm_snprintf(img_name, len, "%s_%s_%u",
+                                       lv->name, layer_name, i) < 0)
+                               return_0;
+               } else {
+                       if (dm_snprintf(img_name, len, "%s_%s",
+                                       lv->name, layer_name) < 0)
+                               return_0;
+               }
+
+               /* FIXME Should use ALLOC_INHERIT here and inherit from parent LV */
+               if (!(sub_lv = lv_create_empty(img_name, NULL,
+                                        LVM_READ | LVM_WRITE,
+                                        lv->alloc, lv->vg)))
+                       return_0;
+
+               if (!set_lv_segment_area_lv(mapseg, i, sub_lv, 0, sub_lv_status))
+                       return_0;
+
+               /* Metadata LVs for raid */
+               if (segtype_is_raid(segtype)) {
+                       if (dm_snprintf(img_name, len, "%s_rmeta_%u", lv->name, i) < 0)
+                               return_0;
+               } else
+                       continue;
+
+               /* FIXME Should use ALLOC_INHERIT here and inherit from parent LV */
+               if (!(sub_lv = lv_create_empty(img_name, NULL,
+                                              LVM_READ | LVM_WRITE,
+                                              lv->alloc, lv->vg)))
+                       return_0;
+
+               if (!set_lv_segment_area_lv(mapseg, i, sub_lv, 0, RAID_META))
+                               return_0;
+       }
+
+       dm_list_add(&lv->segments, &mapseg->list);
+
+       return 1;
+}
+
+static int _lv_extend_layered_lv(struct alloc_handle *ah,
+                                struct logical_volume *lv,
+                                uint32_t extents, uint32_t first_area,
+                                uint32_t stripes, uint32_t stripe_size)
 {
+       const struct segment_type *segtype;
+       struct logical_volume *sub_lv, *meta_lv;
        struct lv_segment *seg;
-       uint32_t m, s;
+       uint32_t fa, s;
+       int clear_metadata = 0;
+
+       segtype = get_segtype_from_string(lv->vg->cmd, "striped");
+
+       /*
+        * The component devices of a "striped" LV all go in the same
+        * LV.  However, RAID has an LV for each device - making the
+        * 'stripes' and 'stripe_size' parameters meaningless.
+        */
+       if (seg_is_raid(first_seg(lv))) {
+               stripes = 1;
+               stripe_size = 0;
+       }
 
        seg = first_seg(lv);
-       for (m = first_area, s = 0; s < seg->area_count; s++) {
+       for (fa = first_area, s = 0; s < seg->area_count; s++) {
                if (is_temporary_mirror_layer(seg_lv(seg, s))) {
-                       if (!_lv_extend_mirror(ah, seg_lv(seg, s), extents, m, stripes, stripe_size))
+                       if (!_lv_extend_layered_lv(ah, seg_lv(seg, s), extents,
+                                                  fa, stripes, stripe_size))
                                return_0;
-                       m += lv_mirror_count(seg_lv(seg, s));
+                       fa += lv_mirror_count(seg_lv(seg, s));
                        continue;
                }
 
-               if (!lv_add_segment(ah, m, stripes, seg_lv(seg, s),
-                                   get_segtype_from_string(lv->vg->cmd,
-                                                           "striped"),
-                                   stripe_size, 0, 0)) {
-                       log_error("Aborting. Failed to extend %s.",
-                                 seg_lv(seg, s)->name);
+               sub_lv = seg_lv(seg, s);
+               if (!lv_add_segment(ah, fa, stripes, sub_lv, segtype,
+                                   stripe_size, sub_lv->status, 0)) {
+                       log_error("Aborting. Failed to extend %s in %s.",
+                                 sub_lv->name, lv->name);
                        return 0;
                }
-               m += stripes;
+
+               /* Extend metadata LVs only on initial creation */
+               if (seg_is_raid(seg) && !lv->le_count) {
+                       if (!seg->meta_areas) {
+                               log_error("No meta_areas for RAID type");
+                               return 0;
+                       }
+
+                       meta_lv = seg_metalv(seg, s);
+                       if (!lv_add_segment(ah, fa + seg->area_count, 1,
+                                           meta_lv, segtype, 0,
+                                           meta_lv->status, 0)) {
+                               log_error("Failed to extend %s in %s.",
+                                         meta_lv->name, lv->name);
+                               return 0;
+                       }
+                       lv_set_visible(meta_lv);
+                       clear_metadata = 1;
+               }
+
+               fa += stripes;
        }
+
+       if (clear_metadata) {
+               /*
+                * We must clear the metadata areas upon creation.
+                */
+               if (!vg_write(lv->vg) || !vg_commit(lv->vg))
+                       return_0;
+
+               for (s = 0; s < seg->area_count; s++) {
+                       meta_lv = seg_metalv(seg, s);
+
+                       if (test_mode()) {
+                               lv_set_hidden(meta_lv);
+                               continue;
+                       }
+
+                       if (!activate_lv(meta_lv->vg->cmd, meta_lv)) {
+                               log_error("Failed to activate %s/%s for clearing",
+                                         meta_lv->vg->name, meta_lv->name);
+                               return 0;
+                       }
+
+                       log_verbose("Clearing metadata area of %s/%s",
+                                   meta_lv->vg->name, meta_lv->name);
+                       /*
+                        * Rather than wiping meta_lv->size, we can simply
+                        * wipe '1' to remove the superblock of any previous
+                        * RAID devices.  It is much quicker.
+                        */
+                       if (!set_lv(meta_lv->vg->cmd, meta_lv, 1, 0)) {
+                               log_error("Failed to zero %s/%s",
+                                         meta_lv->vg->name, meta_lv->name);
+                               return 0;
+                       }
+
+                       if (!deactivate_lv(meta_lv->vg->cmd, meta_lv)) {
+                               log_error("Failed to deactivate %s/%s",
+                                         meta_lv->vg->name, meta_lv->name);
+                               return 0;
+                       }
+                       lv_set_hidden(meta_lv);
+               }
+       }
+
        seg->area_len += extents;
        seg->len += extents;
        lv->le_count += extents;
-       lv->size += (uint64_t) extents *lv->vg->extent_size;
+       lv->size += (uint64_t) extents * lv->vg->extent_size;
+
+       /*
+        * The MD bitmap is limited to being able to track 2^21 regions.
+        * The region_size must be adjusted to meet that criteria.
+        */
+       while (seg_is_raid(seg) && (seg->region_size < (lv->size / (1 << 21)))) {
+               seg->region_size *= 2;
+               log_very_verbose("Forced to adjust RAID region_size to %uS",
+                                seg->region_size);
+       }
 
        return 1;
 }
@@ -1839,28 +2681,113 @@ static int _lv_extend_mirror(struct alloc_handle *ah,
 int lv_extend(struct logical_volume *lv,
              const struct segment_type *segtype,
              uint32_t stripes, uint32_t stripe_size,
-             uint32_t mirrors, uint32_t extents,
-             struct physical_volume *mirrored_pv __attribute__((unused)),
-             uint32_t mirrored_pe __attribute__((unused)),
-             uint64_t status, struct dm_list *allocatable_pvs,
-             alloc_policy_t alloc)
+             uint32_t mirrors, uint32_t region_size,
+             uint32_t extents, const char *thin_pool_name,
+             struct dm_list *allocatable_pvs, alloc_policy_t alloc)
 {
        int r = 1;
+       int log_count = 0;
        struct alloc_handle *ah;
+       uint32_t sub_lv_count;
 
-       if (segtype_is_virtual(segtype))
-               return lv_add_virtual_segment(lv, status, extents, segtype);
+       log_very_verbose("Extending segment type, %s", segtype->name);
 
-       if (!(ah = allocate_extents(lv->vg, lv, segtype, stripes, mirrors, 0, 0,
-                                   extents, allocatable_pvs, alloc, NULL)))
+       if (segtype_is_virtual(segtype))
+               return lv_add_virtual_segment(lv, 0u, extents, segtype, thin_pool_name);
+
+       if (!lv->le_count && segtype_is_thin_pool(segtype)) {
+               /* Thin pool allocation treats its metadata device like a mirror log. */
+               /* FIXME Allow pool and data on same device with NORMAL */
+               /* FIXME Support striped metadata pool */
+               log_count = 1;
+       } else if (segtype_is_raid(segtype) && !lv->le_count)
+               log_count = mirrors * stripes;
+       /* FIXME log_count should be 1 for mirrors */
+
+       if (!(ah = allocate_extents(lv->vg, lv, segtype, stripes, mirrors,
+                                   log_count, region_size, extents,
+                                   allocatable_pvs, alloc, NULL)))
                return_0;
 
-       if (mirrors < 2)
-               r = lv_add_segment(ah, 0, ah->area_count, lv, segtype,
-                                  stripe_size, status, 0);
-       else
-               r = _lv_extend_mirror(ah, lv, extents, 0, stripes, stripe_size);
+       if (segtype_is_thin_pool(segtype)) {
+               if (!lv->le_count) {
+                       if (!(r = extend_pool(lv, segtype, ah, stripes, stripe_size)))
+                               stack;
+               } else if (!(r = _lv_extend_layered_lv(ah, lv, extents, 0,
+                                                      stripes, stripe_size)))
+                       stack;
+       } else if (!segtype_is_mirrored(segtype) && !segtype_is_raid(segtype)) {
+               if (!(r = lv_add_segment(ah, 0, ah->area_count, lv, segtype,
+                                        stripe_size, 0u, 0)))
+                       stack;
+       } else {
+               /*
+                * For RAID, all the devices are AREA_LV.
+                * However, for 'mirror on stripe' using non-RAID targets,
+                * the mirror legs are AREA_LV while the stripes underneath
+                * are AREA_PV.
+                */
+               if (segtype_is_raid(segtype))
+                       sub_lv_count = mirrors * stripes + segtype->parity_devs;
+               else
+                       sub_lv_count = mirrors;
+
+               if (!lv->le_count &&
+                   !(r = _lv_insert_empty_sublvs(lv, segtype, stripe_size,
+                                                 region_size, sub_lv_count))) {
+                       log_error("Failed to insert layer for %s", lv->name);
+                       goto out;
+               }
+
+               if (!(r = _lv_extend_layered_lv(ah, lv, extents, 0,
+                                               stripes, stripe_size)))
+                       goto_out;
+
+               /*
+                * If we are expanding an existing mirror, we can skip the
+                * resync of the extension if the LV is currently in-sync
+                * and the LV has the LV_NOTSYNCED flag set.
+                */
+               if ((lv->le_count != extents) &&
+                   segtype_is_mirrored(segtype) &&
+                   (lv->status & LV_NOTSYNCED)) {
+                       percent_t sync_percent = PERCENT_INVALID;
+
+                       if (!lv_is_active(lv)) {
+                               log_error("%s/%s is not active."
+                                         "  Unable to get sync percent.",
+                                         lv->vg->name, lv->name);
+                               /* FIXME Support --force */
+                               if (yes_no_prompt("Do full resync of extended "
+                                                 "portion of %s/%s?  [y/n]: ",
+                                                 lv->vg->name, lv->name) == 'y')
+                                       goto out;
+                               r = 0;
+                               goto out;
+                       }
 
+                       if (!(r = lv_mirror_percent(lv->vg->cmd, lv, 0,
+                                                   &sync_percent, NULL))) {
+                               log_error("Failed to get sync percent for %s/%s",
+                                         lv->vg->name, lv->name);
+                               goto out;
+                       } else if (sync_percent == PERCENT_100) {
+                               log_verbose("Skipping initial resync for "
+                                           "extended portion of %s/%s",
+                                           lv->vg->name, lv->name);
+                               init_mirror_in_sync(1);
+                               lv->status |= LV_NOTSYNCED;
+                       } else {
+                               log_error("%s/%s cannot be extended while"
+                                         " it is recovering.",
+                                         lv->vg->name, lv->name);
+                               r = 0;
+                               goto out;
+                       }
+               }
+       }
+
+out:
        alloc_destroy(ah);
        return r;
 }
@@ -1898,7 +2825,8 @@ static int _rename_sub_lv(struct cmd_context *cmd,
                          struct logical_volume *lv,
                          const char *lv_name_old, const char *lv_name_new)
 {
-       char *suffix, *new_name;
+       const char *suffix;
+       char *new_name;
        size_t len;
 
        /*
@@ -1926,7 +2854,7 @@ static int _rename_sub_lv(struct cmd_context *cmd,
                log_error("Failed to allocate space for new name");
                return 0;
        }
-       if (!dm_snprintf(new_name, len, "%s%s", lv_name_new, suffix)) {
+       if (dm_snprintf(new_name, len, "%s%s", lv_name_new, suffix) < 0) {
                log_error("Failed to create new name");
                return 0;
        }
@@ -1935,7 +2863,7 @@ static int _rename_sub_lv(struct cmd_context *cmd,
        return _rename_single_lv(lv, new_name);
 }
 
-/* Callback for _for_each_sub_lv */
+/* Callback for for_each_sub_lv */
 static int _rename_cb(struct cmd_context *cmd, struct logical_volume *lv,
                      void *data)
 {
@@ -1945,32 +2873,59 @@ static int _rename_cb(struct cmd_context *cmd, struct logical_volume *lv,
 }
 
 /*
- * Loop down sub LVs and call "func" for each.
- * "func" is responsible to log necessary information on failure.
+ * Loop down sub LVs and call fn for each.
+ * fn is responsible to log necessary information on failure.
  */
-static int _for_each_sub_lv(struct cmd_context *cmd, struct logical_volume *lv,
-                           int (*func)(struct cmd_context *cmd,
-                                       struct logical_volume *lv,
-                                       void *data),
-                           void *data)
+int for_each_sub_lv(struct cmd_context *cmd, struct logical_volume *lv,
+                   int (*fn)(struct cmd_context *cmd,
+                             struct logical_volume *lv, void *data),
+                   void *data)
 {
        struct logical_volume *org;
        struct lv_segment *seg;
        uint32_t s;
 
-       if (lv_is_cow(lv) && lv_is_virtual_origin(org = origin_from_cow(lv)))
-               if (!func(cmd, org, data))
+       if (lv_is_cow(lv) && lv_is_virtual_origin(org = origin_from_cow(lv))) {
+               if (!fn(cmd, org, data))
                        return_0;
+               if (!for_each_sub_lv(cmd, org, fn, data))
+                       return_0;
+       }
+
+       dm_list_iterate_items(seg, &lv->segments) {
+               if (seg->log_lv) {
+                       if (!fn(cmd, seg->log_lv, data))
+                               return_0;
+                       if (!for_each_sub_lv(cmd, seg->log_lv, fn, data))
+                               return_0;
+               }
+
+               if (seg->metadata_lv) {
+                       if (!fn(cmd, seg->metadata_lv, data))
+                               return_0;
+                       if (!for_each_sub_lv(cmd, seg->metadata_lv, fn, data))
+                               return_0;
+               }
 
-       dm_list_iterate_items(seg, &lv->segments) {
-               if (seg->log_lv && !func(cmd, seg->log_lv, data))
-                       return_0;
                for (s = 0; s < seg->area_count; s++) {
                        if (seg_type(seg, s) != AREA_LV)
                                continue;
-                       if (!func(cmd, seg_lv(seg, s), data))
+                       if (!fn(cmd, seg_lv(seg, s), data))
+                               return_0;
+                       if (!for_each_sub_lv(cmd, seg_lv(seg, s), fn, data))
+                               return_0;
+               }
+
+               if (!seg_is_raid(seg))
+                       continue;
+
+               /* RAID has meta_areas */
+               for (s = 0; s < seg->area_count; s++) {
+                       if (seg_metatype(seg, s) != AREA_LV)
+                               continue;
+                       if (!fn(cmd, seg_metalv(seg, s), data))
                                return_0;
-                       if (!_for_each_sub_lv(cmd, seg_lv(seg, s), func, data))
+                       if (!for_each_sub_lv(cmd, seg_metalv(seg, s), fn, data))
                                return_0;
                }
        }
@@ -1983,8 +2938,8 @@ static int _for_each_sub_lv(struct cmd_context *cmd, struct logical_volume *lv,
  * Core of LV renaming routine.
  * VG must be locked by caller.
  */
-int lv_rename(struct cmd_context *cmd, struct logical_volume *lv,
-             const char *new_name)
+int lv_rename_update(struct cmd_context *cmd, struct logical_volume *lv,
+                    const char *new_name, int update_mda)
 {
        struct volume_group *vg = lv->vg;
        struct lv_names lv_names;
@@ -2009,13 +2964,13 @@ int lv_rename(struct cmd_context *cmd, struct logical_volume *lv,
                return 0;
        }
 
-       if (!archive(vg))
+       if (update_mda && !archive(vg))
                return 0;
 
        /* rename sub LVs */
        lv_names.old = lv->name;
        lv_names.new = new_name;
-       if (!_for_each_sub_lv(cmd, lv, _rename_cb, (void *) &lv_names))
+       if (!for_each_sub_lv(cmd, lv, _rename_cb, (void *) &lv_names))
                return 0;
 
        /* rename main LV */
@@ -2031,15 +2986,15 @@ int lv_rename(struct cmd_context *cmd, struct logical_volume *lv,
        if (lv_is_cow(lv) && lv_is_virtual_origin(lvl2.lv = origin_from_cow(lv)))
                dm_list_add_h(&lvs_changed, &lvl2.list);
 
+       if (!update_mda)
+               return 1;
+
        log_verbose("Writing out updated volume group");
        if (!vg_write(vg))
                return 0;
 
-
-       if (!suspend_lvs(cmd, &lvs_changed)) {
-               vg_revert(vg);
+       if (!suspend_lvs(cmd, &lvs_changed, vg))
                goto_out;
-       }
 
        if (!(r = vg_commit(vg)))
                stack;
@@ -2057,6 +3012,16 @@ out:
        return r;
 }
 
+/*
+ * Core of LV renaming routine.
+ * VG must be locked by caller.
+ */
+int lv_rename(struct cmd_context *cmd, struct logical_volume *lv,
+             const char *new_name)
+{
+       return lv_rename_update(cmd, lv, new_name, 1);
+}
+
 char *generate_lv_name(struct volume_group *vg, const char *format,
                       char *buffer, size_t len)
 {
@@ -2158,6 +3123,9 @@ struct logical_volume *lv_create_empty(const char *name,
 
        if (!link_lv_to_vg(vg, lv))
                goto_bad;
+
+       if (!lv_set_creation(lv, NULL, 0))
+               goto_bad;
  
        if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv))
                goto_bad;
@@ -2194,14 +3162,15 @@ static int _add_pvs(struct cmd_context *cmd, struct pv_segment *peg,
  * Construct dm_list of segments of LVs showing which PVs they use.
  * For pvmove we use the *parent* LV so we can pick up stripes & existing mirrors etc.
  */
-struct dm_list *build_parallel_areas_from_lv(struct cmd_context *cmd,
-                                            struct logical_volume *lv,
+struct dm_list *build_parallel_areas_from_lv(struct logical_volume *lv,
                                             unsigned use_pvmove_parent_lv)
 {
+       struct cmd_context *cmd = lv->vg->cmd;
        struct dm_list *parallel_areas;
        struct seg_pvs *spvs;
        uint32_t current_le = 0;
-       struct lv_segment * uninitialized_var(seg);
+       uint32_t raid_multiple;
+       struct lv_segment *seg = first_seg(lv);
 
        if (!(parallel_areas = dm_pool_alloc(cmd->mem, sizeof(*parallel_areas)))) {
                log_error("parallel_areas allocation failed");
@@ -2240,7 +3209,9 @@ struct dm_list *build_parallel_areas_from_lv(struct cmd_context *cmd,
                        return_NULL;
 
                current_le = spvs->le + spvs->len;
-       } while (current_le < lv->le_count);
+               raid_multiple = (seg->segtype->parity_devs) ?
+                       seg->area_count - seg->segtype->parity_devs : 1;
+       } while ((current_le * raid_multiple) < lv->le_count);
 
        /* FIXME Merge adjacent segments with identical PV lists (avoids need for contiguous allocation attempts between successful allocations) */
 
@@ -2301,13 +3272,16 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
 {
        struct volume_group *vg;
        struct lvinfo info;
-       struct logical_volume *origin = NULL;
-       int was_merging = 0;
+       struct logical_volume *format1_origin = NULL;
+       int format1_reload_required = 0;
+       int visible;
+       struct logical_volume *pool_lv = NULL;
+       int ask_discard;
 
        vg = lv->vg;
 
        if (!vg_check_status(vg, LVM_WRITE))
-               return 0;
+               return_0;
 
        if (lv_is_origin(lv)) {
                log_error("Can't remove logical volume \"%s\" under snapshot",
@@ -2327,75 +3301,129 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
                return 0;
        }
 
+       if (lv->status & (RAID_META | RAID_IMAGE)) {
+               log_error("Can't remove logical volume %s used as RAID device",
+                         lv->name);
+               return 0;
+       }
+
+       if (lv_is_thin_pool_data(lv) || lv_is_thin_pool_metadata(lv)) {
+               log_error("Can't remove logical volume %s used by a thin pool.",
+                         lv->name);
+               return 0;
+       } else if (lv_is_thin_volume(lv))
+               pool_lv = first_seg(lv)->pool_lv;
+
        if (lv->status & LOCKED) {
                log_error("Can't remove locked LV %s", lv->name);
                return 0;
        }
 
        /* FIXME Ensure not referred to by another existing LVs */
+       ask_discard = find_config_tree_bool(cmd,
+                                           "devices/issue_discards", DEFAULT_ISSUE_DISCARDS);
 
        if (lv_info(cmd, lv, 0, &info, 1, 0)) {
-               if (info.open_count) {
-                       log_error("Can't remove open logical volume \"%s\"",
-                                 lv->name);
-                       return 0;
-               }
+               if (!lv_check_not_in_use(cmd, lv, &info))
+                       return_0;
 
-               if (lv_is_active(lv) && (force == PROMPT) &&
+               if ((force == PROMPT) &&
                    lv_is_visible(lv) &&
-                   yes_no_prompt("Do you really want to remove active "
-                                 "%slogical volume %s? [y/n]: ",
-                                 vg_is_clustered(vg) ? "clustered " : "",
-                                 lv->name) == 'n') {
-                       log_error("Logical volume %s not removed", lv->name);
-                       return 0;
+                   lv_is_active(lv)) {
+                       if (yes_no_prompt("Do you really want to remove%s active "
+                                         "%slogical volume %s? [y/n]: ",
+                                         ask_discard ? " and DISCARD" : "",
+                                         vg_is_clustered(vg) ? "clustered " : "",
+                                         lv->name) == 'n') {
+                               log_error("Logical volume %s not removed", lv->name);
+                               return 0;
+                       } else {
+                               ask_discard = 0;
+                       }
                }
        }
 
+       if ((force == PROMPT) && ask_discard &&
+           yes_no_prompt("Do you really want to remove and DISCARD "
+                         "logical volume %s? [y/n]: ",
+                         lv->name) == 'n') {
+               log_error("Logical volume %s not removed", lv->name);
+               return 0;
+       }
+
        if (!archive(vg))
                return 0;
 
        if (lv_is_cow(lv)) {
-               origin = origin_from_cow(lv);
-               was_merging = lv_is_merging_origin(origin);
+               /* Old format1 code */
+               if (!(lv->vg->fid->fmt->features & FMT_MDAS))
+                       format1_origin = origin_from_cow(lv);
+
                log_verbose("Removing snapshot %s", lv->name);
-               /* vg_remove_snapshot() will preload origin if it was merging */
+               /* vg_remove_snapshot() will preload origin/former snapshots */
                if (!vg_remove_snapshot(lv))
                        return_0;
        }
 
+       /* FIXME Review and fix the snapshot error paths! */
        if (!deactivate_lv(cmd, lv)) {
                log_error("Unable to deactivate logical volume \"%s\"",
                          lv->name);
                return 0;
        }
 
+       /* Clear thin pool stacked messages */
+       if (pool_lv && !pool_has_message(first_seg(pool_lv), lv, 0) &&
+           !update_pool_lv(pool_lv, 1)) {
+               log_error("Failed to update thin pool %s.", pool_lv->name);
+               return 0;
+       }
+
+       visible = lv_is_visible(lv);
+
        log_verbose("Releasing logical volume \"%s\"", lv->name);
        if (!lv_remove(lv)) {
                log_error("Error releasing logical volume \"%s\"", lv->name);
                return 0;
        }
 
+       /*
+        * Old format1 code: If no snapshots left reload without -real.
+        */
+       if (format1_origin && !lv_is_origin(format1_origin)) {
+               log_warn("WARNING: Support for snapshots with old LVM1-style metadata is deprecated.");
+               log_warn("WARNING: Please use lvconvert to update to lvm2 metadata at your convenience.");
+               format1_reload_required = 1;
+       }
+
        /* store it on disks */
-       if (!vg_write(vg) || !vg_commit(vg))
+       if (!vg_write(vg))
                return_0;
 
-       /* If no snapshots left, and was not merging, reload without -real. */
-       if (origin && (!lv_is_origin(origin) && !was_merging)) {
-               if (!suspend_lv(cmd, origin)) {
-                       log_error("Failed to refresh %s without snapshot.", origin->name);
-                       return 0;
-               }
-               if (!resume_lv(cmd, origin)) {
-                       log_error("Failed to resume %s.", origin->name);
-                       return 0;
-               }
+       /* format1 */
+       if (format1_reload_required && !suspend_lv(cmd, format1_origin))
+               log_error("Failed to refresh %s without snapshot.", format1_origin->name);
+
+       if (!vg_commit(vg))
+               return_0;
+       /* format1 */
+       if (format1_reload_required && !resume_lv(cmd, format1_origin)) {
+               log_error("Failed to resume %s.", format1_origin->name);
+               return 0;
+       }
+
+       /* Release unneeded blocks in thin pool */
+       /* TODO: defer when multiple LVs relased at once */
+       if (pool_lv && !update_pool_lv(pool_lv, 1)) {
+               log_error("Failed to update thin pool %s.", pool_lv->name);
+               return 0;
        }
 
        backup(vg);
 
-       if (lv_is_visible(lv))
-               log_print("Logical volume \"%s\" successfully removed", lv->name);
+       if (visible)
+               log_print_unless_silent("Logical volume \"%s\" successfully removed", lv->name);
 
        return 1;
 }
@@ -2406,25 +3434,74 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
 int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume *lv,
                                const force_t force, unsigned level)
 {
+       percent_t snap_percent;
        struct dm_list *snh, *snht;
+       struct seg_list *sl, *tsl;
+       struct lvinfo info;
 
        if (lv_is_cow(lv)) {
-               /* A merging snapshot cannot be removed directly */
+               /*
+                * A merging snapshot cannot be removed directly unless
+                * it has been invalidated or failed merge removal is requested.
+                */
                if (lv_is_merging_cow(lv) && !level) {
-                       log_error("Can't remove merging snapshot logical volume \"%s\"",
-                                 lv->name);
-                       return 0;
+                       if (lv_info(lv->vg->cmd, lv, 0, &info, 1, 0) &&
+                           info.exists && info.live_table) {
+                               if (!lv_snapshot_percent(lv, &snap_percent)) {
+                                       log_error("Failed to obtain merging snapshot progress percentage for logical volume %s.",
+                                                 lv->name);
+                                       return 0;
+                               }
+                               if ((snap_percent != PERCENT_INVALID) &&
+                                    (snap_percent != PERCENT_MERGE_FAILED)) {
+                                       log_error("Can't remove merging snapshot logical volume \"%s\"",
+                                                 lv->name);
+                                       return 0;
+                               } else if ((snap_percent == PERCENT_MERGE_FAILED) &&
+                                        (force == PROMPT) &&
+                                        yes_no_prompt("Removing snapshot \"%s\" that failed to merge may leave origin \"%s\" inconsistent. "
+                                                      "Proceed? [y/n]: ", lv->name, origin_from_cow(lv)->name) == 'n') {
+                                       log_error("Logical volume %s not removed.", lv->name);
+                                       return 0;
+                               }
+                       }
                }
        }
 
        if (lv_is_origin(lv)) {
-               /* remove snapshot LVs first */
-               dm_list_iterate_safe(snh, snht, &lv->snapshot_segs) {
+               /* Remove snapshot LVs first */
+               if ((force == PROMPT) &&
+                   /* Active snapshot already needs to confirm each active LV */
+                   !lv_is_active(lv) &&
+                   yes_no_prompt("Removing origin %s will also remove %u "
+                                 "snapshots(s). Proceed? [y/n]: ",
+                                 lv->name, lv->origin_count) == 'n') {
+                       log_error("Logical volume %s not removed.", lv->name);
+                       return 0;
+               }
+
+               dm_list_iterate_safe(snh, snht, &lv->snapshot_segs)
                        if (!lv_remove_with_dependencies(cmd, dm_list_struct_base(snh, struct lv_segment,
                                                                                  origin_list)->cow,
                                                         force, level + 1))
-                               return 0;
+                               return_0;
+       }
+
+       if (lv_is_used_thin_pool(lv)) {
+               /* Remove thin LVs first */
+               if ((force == PROMPT) &&
+                   yes_no_prompt("Removing pool %s will also remove %u "
+                                 "thin volume(s). OK? [y/n]: ", lv->name,
+                                 /* Note: Snaphosts not included */
+                                 dm_list_size(&lv->segs_using_this_lv)) == 'n') {
+                       log_error("Logical volume %s not removed.", lv->name);
+                       return 0;
                }
+
+               dm_list_iterate_items_safe(sl, tsl, &lv->segs_using_this_lv)
+                       if (!lv_remove_with_dependencies(cmd, sl->seg->lv,
+                                                        force, level + 1))
+                               return_0;
        }
 
        return lv_remove_single(cmd, lv, force);
@@ -2495,7 +3572,7 @@ int split_parent_segments_for_layer(struct cmd_context *cmd,
        uint32_t s;
        struct dm_list *parallel_areas;
 
-       if (!(parallel_areas = build_parallel_areas_from_lv(cmd, layer_lv, 0)))
+       if (!(parallel_areas = build_parallel_areas_from_lv(layer_lv, 0)))
                return_0;
 
        /* Loop through all LVs except itself */
@@ -2628,22 +3705,20 @@ int remove_layers_for_segments_all(struct cmd_context *cmd,
        return 1;
 }
 
-static int _move_lv_segments(struct logical_volume *lv_to,
-                            struct logical_volume *lv_from,
-                            uint64_t set_status, uint64_t reset_status)
+int move_lv_segments(struct logical_volume *lv_to,
+                    struct logical_volume *lv_from,
+                    uint64_t set_status, uint64_t reset_status)
 {
        struct lv_segment *seg;
 
-       dm_list_iterate_items(seg, &lv_to->segments) {
+       dm_list_iterate_items(seg, &lv_to->segments)
                if (seg->origin) {
-                       log_error("Can't move snapshot segment");
+                       log_error("Can't move snapshot segment.");
                        return 0;
                }
-       }
 
-       lv_to->segments = lv_from->segments;
-       lv_to->segments.n->p = &lv_to->segments;
-       lv_to->segments.p->n = &lv_to->segments;
+       dm_list_init(&lv_to->segments);
+       dm_list_splice(&lv_to->segments, &lv_from->segments);
 
        dm_list_iterate_items(seg, &lv_to->segments) {
                seg->lv = lv_to;
@@ -2651,8 +3726,6 @@ static int _move_lv_segments(struct logical_volume *lv_to,
                seg->status |= set_status;
        }
 
-       dm_list_init(&lv_from->segments);
-
        lv_to->le_count = lv_from->le_count;
        lv_to->size = lv_from->size;
 
@@ -2693,12 +3766,12 @@ int remove_layer_from_lv(struct logical_volume *lv,
        if (!lv_empty(parent))
                return_0;
 
-       if (!_move_lv_segments(parent, layer_lv, 0, 0))
+       if (!move_lv_segments(parent, layer_lv, 0, 0))
                return_0;
 
        /* Replace the empty layer with error segment */
        segtype = get_segtype_from_string(lv->vg->cmd, "error");
-       if (!lv_add_virtual_segment(layer_lv, 0, parent->le_count, segtype))
+       if (!lv_add_virtual_segment(layer_lv, 0, parent->le_count, segtype, NULL))
                return_0;
 
        return 1;
@@ -2715,11 +3788,15 @@ struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
                                           uint64_t status,
                                           const char *layer_suffix)
 {
-       struct logical_volume *layer_lv;
+       int r;
        char *name;
        size_t len;
+       struct str_list *sl;
+       struct logical_volume *layer_lv;
        struct segment_type *segtype;
        struct lv_segment *mapseg;
+       struct lv_names lv_names;
+       unsigned exclusive = 0;
 
        /* create an empty layer LV */
        len = strlen(lv_where->name) + 32;
@@ -2741,16 +3818,27 @@ struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
                return NULL;
        }
 
+       if (lv_is_active_exclusive_locally(lv_where))
+               exclusive = 1;
+
        if (lv_is_active(lv_where) && strstr(name, "_mimagetmp")) {
                log_very_verbose("Creating transient LV %s for mirror conversion in VG %s.", name, lv_where->vg->name);
 
                segtype = get_segtype_from_string(cmd, "error");
 
-               if (!lv_add_virtual_segment(layer_lv, 0, lv_where->le_count, segtype)) {
+               if (!lv_add_virtual_segment(layer_lv, 0, lv_where->le_count, segtype, NULL)) {
                        log_error("Creation of transient LV %s for mirror conversion in VG %s failed.", name, lv_where->vg->name);
                        return NULL;
                }
 
+               /* Temporary tags for activation of the transient LV */
+               dm_list_iterate_items(sl, &lv_where->tags)
+                       if (!str_list_add(cmd->mem, &layer_lv->tags, sl->str)) {
+                               log_error("Aborting.  Unable to tag"
+                                         " transient mirror layer.");
+                               return NULL;
+                       }
+
                if (!vg_write(lv_where->vg)) {
                        log_error("Failed to write intermediate VG %s metadata for mirror conversion.", lv_where->vg->name);
                        return NULL;
@@ -2762,25 +3850,36 @@ struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
                        return NULL;
                }
 
-               if (!activate_lv(cmd, layer_lv)) {
-                       log_error("Failed to resume transient error LV %s for mirror conversion in VG %s.", name, lv_where->vg->name);
+               if (exclusive)
+                       r = activate_lv_excl(cmd, layer_lv);
+               else
+                       r = activate_lv(cmd, layer_lv);
+
+               if (!r) {
+                       log_error("Failed to resume transient LV"
+                                 " %s for mirror conversion in VG %s.",
+                                 name, lv_where->vg->name);
                        return NULL;
                }
+
+               /* Remove the temporary tags */
+               dm_list_iterate_items(sl, &lv_where->tags)
+                       str_list_del(&layer_lv->tags, sl->str);
+
        }
 
        log_very_verbose("Inserting layer %s for %s",
                         layer_lv->name, lv_where->name);
 
-       if (!_move_lv_segments(layer_lv, lv_where, 0, 0))
+       if (!move_lv_segments(layer_lv, lv_where, 0, 0))
                return_NULL;
 
        if (!(segtype = get_segtype_from_string(cmd, "striped")))
                return_NULL;
 
        /* allocate a new linear segment */
-       if (!(mapseg = alloc_lv_segment(cmd->mem, segtype,
-                                       lv_where, 0, layer_lv->le_count,
-                                       status, 0, NULL, 1, layer_lv->le_count,
+       if (!(mapseg = alloc_lv_segment(segtype, lv_where, 0, layer_lv->le_count,
+                                       status, 0, NULL, NULL, 1, layer_lv->le_count,
                                        0, 0, 0, NULL)))
                return_NULL;
 
@@ -2791,7 +3890,19 @@ struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
        /* add the new segment to the layer LV */
        dm_list_add(&lv_where->segments, &mapseg->list);
        lv_where->le_count = layer_lv->le_count;
-       lv_where->size = lv_where->le_count * lv_where->vg->extent_size;
+       lv_where->size = (uint64_t) lv_where->le_count * lv_where->vg->extent_size;
+
+       /*
+        * recuresively rename sub LVs
+        *   currently supported only for thin data layer
+        *   FIXME: without strcmp it breaks mirrors....
+        */
+       if (strcmp(layer_suffix, "_tdata") == 0) {
+               lv_names.old = lv_where->name;
+               lv_names.new = layer_lv->name;
+               if (!for_each_sub_lv(cmd, layer_lv, _rename_cb, (void *) &lv_names))
+                       return 0;
+       }
 
        return layer_lv;
 }
@@ -2821,10 +3932,9 @@ static int _extend_layer_lv_for_segment(struct logical_volume *layer_lv,
                         seg->lv->vg->name, seg->lv->name);
 
        /* allocate a new segment */
-       if (!(mapseg = alloc_lv_segment(layer_lv->vg->cmd->mem, segtype,
-                                       layer_lv, layer_lv->le_count,
+       if (!(mapseg = alloc_lv_segment(segtype, layer_lv, layer_lv->le_count,
                                        seg->area_len, status, 0,
-                                       NULL, 1, seg->area_len, 0, 0, 0, seg)))
+                                       NULL, NULL, 1, seg->area_len, 0, 0, 0, seg)))
                return_0;
 
        /* map the new segment to the original underlying are */
@@ -2834,7 +3944,7 @@ static int _extend_layer_lv_for_segment(struct logical_volume *layer_lv,
        /* add the new segment to the layer LV */
        dm_list_add(&layer_lv->segments, &mapseg->list);
        layer_lv->le_count += seg->area_len;
-       layer_lv->size += seg->area_len * layer_lv->vg->extent_size;
+       layer_lv->size += (uint64_t) seg->area_len * layer_lv->vg->extent_size;
 
        /* map the original area to the new segment */
        if (!set_lv_segment_area_lv(seg, s, layer_lv, mapseg->le, 0))
@@ -3022,6 +4132,8 @@ int set_lv(struct cmd_context *cmd, struct logical_volume *lv,
                return 0;
        }
 
+       sync_local_dev_names(cmd);  /* Wait until devices are available */
+
        log_verbose("Clearing start of logical volume \"%s\"", lv->name);
 
        if (!(dev = dev_cache_get(name, NULL))) {
@@ -3044,12 +4156,11 @@ int set_lv(struct cmd_context *cmd, struct logical_volume *lv,
        dev_flush(dev);
 
        if (!dev_close_immediate(dev))
-                stack;
+               stack;
 
        return 1;
 }
 
-
 static struct logical_volume *_create_virtual_origin(struct cmd_context *cmd,
                                                     struct volume_group *vg,
                                                     const char *lv_name,
@@ -3077,8 +4188,8 @@ static struct logical_volume *_create_virtual_origin(struct cmd_context *cmd,
                                   ALLOC_INHERIT, vg)))
                return_NULL;
 
-       if (!lv_extend(lv, segtype, 1, 0, 1, voriginextents, NULL, 0u, 0u,
-                      NULL, ALLOC_INHERIT))
+       if (!lv_extend(lv, segtype, 1, 0, 1, 0, voriginextents,
+                      NULL, NULL, ALLOC_INHERIT))
                return_NULL;
 
        /* store vg on disk(s) */
@@ -3090,31 +4201,42 @@ static struct logical_volume *_create_virtual_origin(struct cmd_context *cmd,
        return lv;
 }
 
-int lv_create_single(struct volume_group *vg,
-                    struct lvcreate_params *lp)
+/* Thin notes:
+ * If lp->thin OR lp->activate is AY*, activate the pool if not already active.
+ * If lp->thin, create thin LV within the pool - as a snapshot if lp->snapshot.
+ *   If lp->activate is AY*, activate it.
+ *   If lp->activate was AN* and the pool was originally inactive, deactivate it.
+ */
+static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, struct lvcreate_params *lp,
+                                              const char *new_lv_name)
 {
        struct cmd_context *cmd = vg->cmd;
        uint32_t size_rest;
        uint64_t status = UINT64_C(0);
        struct logical_volume *lv, *org = NULL;
+       struct logical_volume *pool_lv;
+       struct lv_list *lvl;
        int origin_active = 0;
        struct lvinfo info;
 
-       if (lp->lv_name && find_lv_in_vg(vg, lp->lv_name)) {
+       if (new_lv_name && find_lv_in_vg(vg, new_lv_name)) {
                log_error("Logical volume \"%s\" already exists in "
-                         "volume group \"%s\"", lp->lv_name, lp->vg_name);
-               return 0;
+                         "volume group \"%s\"", new_lv_name, lp->vg_name);
+               return NULL;
        }
 
        if (vg_max_lv_reached(vg)) {
                log_error("Maximum number of logical volumes (%u) reached "
                          "in volume group %s", vg->max_lv, vg->name);
-               return 0;
+               return NULL;
        }
 
-       if (lp->mirrors > 1 && !(vg->fid->fmt->features & FMT_SEGMENTS)) {
-               log_error("Metadata does not support mirroring.");
-               return 0;
+       if ((segtype_is_mirrored(lp->segtype) ||
+            segtype_is_raid(lp->segtype) || segtype_is_thin(lp->segtype)) &&
+           !(vg->fid->fmt->features & FMT_SEGMENTS)) {
+               log_error("Metadata does not support %s segments.",
+                         lp->segtype->name);
+               return NULL;
        }
 
        if (lp->read_ahead != DM_READ_AHEAD_AUTO &&
@@ -3122,7 +4244,7 @@ int lv_create_single(struct volume_group *vg,
            (vg->fid->fmt->features & FMT_RESTRICTED_READAHEAD) &&
            (lp->read_ahead < 2 || lp->read_ahead > 120)) {
                log_error("Metadata only supports readahead values between 2 and 120.");
-               return 0;
+               return NULL;
        }
 
        if (lp->stripe_size > vg->extent_size) {
@@ -3139,34 +4261,43 @@ int lv_create_single(struct volume_group *vg,
            (lp->stripe_size > STRIPE_SIZE_MAX)) {
                log_error("Stripe size may not exceed %s",
                          display_size(cmd, (uint64_t) STRIPE_SIZE_MAX));
-               return 0;
+               return NULL;
        }
 
        if ((size_rest = lp->extents % lp->stripes)) {
-               log_print("Rounding size (%d extents) up to stripe boundary "
-                         "size (%d extents)", lp->extents,
+               log_print_unless_silent("Rounding size (%d extents) up to stripe boundary "
+                                       "size (%d extents)", lp->extents,
                          lp->extents - size_rest + lp->stripes);
                lp->extents = lp->extents - size_rest + lp->stripes;
        }
 
-       if (lp->zero && !activation()) {
+       /* Does LV need to be zeroed?  Thin handles this as a per-pool in-kernel setting. */
+       if (lp->zero && !segtype_is_thin(lp->segtype) && !activation()) {
                log_error("Can't wipe start of new LV without using "
                          "device-mapper kernel driver");
-               return 0;
+               return NULL;
        }
 
        status |= lp->permission | VISIBLE_LV;
 
-       if (lp->snapshot) {
+       if (lp->snapshot && lp->thin) {
+               if (!(org = find_lv(vg, lp->origin))) {
+                       log_error("Couldn't find origin volume '%s'.",
+                                 lp->origin);
+                       return NULL;
+               }
+
+               if (org->status & LOCKED) {
+                       log_error("Snapshots of locked devices are not supported.");
+                       return NULL;
+               }
+
+               lp->voriginextents = org->le_count;
+       } else if (lp->snapshot) {
                if (!activation()) {
                        log_error("Can't create snapshot without using "
                                  "device-mapper kernel driver");
-                       return 0;
-               }
-               /* FIXME Allow exclusive activation. */
-               if (vg_is_clustered(vg)) {
-                       log_error("Clustered snapshots are not yet supported.");
-                       return 0;
+                       return NULL;
                }
 
                /* Must zero cow */
@@ -3179,112 +4310,180 @@ int lv_create_single(struct volume_group *vg,
                        if (!(org = find_lv(vg, lp->origin))) {
                                log_error("Couldn't find origin volume '%s'.",
                                          lp->origin);
-                               return 0;
+                               return NULL;
                        }
                        if (lv_is_virtual_origin(org)) {
                                log_error("Can't share virtual origins. "
                                          "Use --virtualsize.");
-                               return 0;
+                               return NULL;
                        }
                        if (lv_is_cow(org)) {
                                log_error("Snapshots of snapshots are not "
                                          "supported yet.");
-                               return 0;
+                               return NULL;
                        }
                        if (org->status & LOCKED) {
                                log_error("Snapshots of locked devices are not "
                                          "supported yet");
-                               return 0;
+                               return NULL;
                        }
                        if (lv_is_merging_origin(org)) {
                                log_error("Snapshots of an origin that has a "
                                          "merging snapshot is not supported");
-                               return 0;
+                               return NULL;
                        }
-                       if ((org->status & MIRROR_IMAGE) ||
-                           (org->status & MIRROR_LOG)) {
-                               log_error("Snapshots of mirror %ss "
-                                         "are not supported",
-                                         (org->status & MIRROR_LOG) ?
-                                         "log" : "image");
-                               return 0;
+
+                       if (lv_is_thin_type(org) && !lv_is_thin_volume(org)) {
+                               log_error("Snapshots of thin pool %sdevices "
+                                         "are not supported.",
+                                         lv_is_thin_pool_data(org) ? "data " :
+                                         lv_is_thin_pool_metadata(org) ?
+                                         "metadata " : "");
+                               return NULL;
+                       }
+
+                       if (lv_is_mirror_type(org) &&
+                           !seg_is_raid(first_seg(org))) {
+                               log_warn("WARNING: Snapshots of mirrors can deadlock under rare device failures.");
+                               log_warn("WARNING: Consider using the raid1 mirror type to avoid this.");
+                               log_warn("WARNING: See global/mirror_segtype_default in lvm.conf.");
                        }
 
                        if (!lv_info(cmd, org, 0, &info, 0, 0)) {
-                               log_error("Check for existence of snapshot "
+                               log_error("Check for existence of active snapshot "
                                          "origin '%s' failed.", org->name);
-                               return 0;
+                               return NULL;
                        }
                        origin_active = info.exists;
+
+                       if (vg_is_clustered(vg) &&
+                           !lv_is_active_exclusive_locally(org)) {
+                               log_error("%s must be active exclusively to"
+                                         " create snapshot", org->name);
+                               return NULL;
+                       }
                }
        }
 
-       if (!lp->extents) {
+       if (!seg_is_thin_volume(lp) && !lp->extents) {
                log_error("Unable to create new logical volume with no extents");
-               return 0;
+               return NULL;
+       }
+
+       if (seg_is_thin_pool(lp) &&
+           ((uint64_t)lp->extents * vg->extent_size < lp->chunk_size)) {
+               log_error("Unable to create thin pool smaller than 1 chunk.");
+               return NULL;
        }
 
-       if (lp->snapshot && (lp->extents * vg->extent_size < 2 * lp->chunk_size)) {
+       if (lp->snapshot && !lp->thin && ((uint64_t)lp->extents * vg->extent_size < 2 * lp->chunk_size)) {
                log_error("Unable to create a snapshot smaller than 2 chunks.");
-               return 0;
+               return NULL;
        }
 
        if (!seg_is_virtual(lp) &&
            vg->free_count < lp->extents) {
-               log_error("Insufficient free extents (%u) in volume group %s: "
-                         "%u required", vg->free_count, vg->name, lp->extents);
-               return 0;
+               log_error("Volume group \"%s\" has insufficient free space "
+                         "(%u extents): %u required.",
+                         vg->name, vg->free_count, lp->extents);
+               return NULL;
        }
 
        if (lp->stripes > dm_list_size(lp->pvh) && lp->alloc != ALLOC_ANYWHERE) {
                log_error("Number of stripes (%u) must not exceed "
                          "number of physical volumes (%d)", lp->stripes,
                          dm_list_size(lp->pvh));
-               return 0;
+               return NULL;
        }
 
-       if (lp->mirrors > 1 && !activation()) {
-               log_error("Can't create mirror without using "
-                         "device-mapper kernel driver.");
-               return 0;
+       if (!activation() &&
+           (seg_is_mirrored(lp) ||
+            seg_is_raid(lp) ||
+            seg_is_thin_pool(lp))) {
+               /*
+                * FIXME: For thin pool add some code to allow delayed
+                * initialization of empty thin pool volume.
+                * i.e. using some LV flag, fake message,...
+                * and testing for metadata pool header signature?
+                */
+               log_error("Can't create %s without using "
+                         "device-mapper kernel driver.",
+                         segtype_is_raid(lp->segtype) ? lp->segtype->name :
+                         segtype_is_mirrored(lp->segtype) ?  "mirror" :
+                         "thin pool volume");
+               return NULL;
        }
 
        /* The snapshot segment gets created later */
-       if (lp->snapshot &&
+       if (lp->snapshot && !lp->thin &&
            !(lp->segtype = get_segtype_from_string(cmd, "striped")))
-               return_0;
+               return_NULL;
 
        if (!archive(vg))
-               return 0;
+               return_NULL;
 
        if (!dm_list_empty(&lp->tags)) {
                if (!(vg->fid->fmt->features & FMT_TAGS)) {
                        log_error("Volume group %s does not support tags",
                                  vg->name);
-                       return 0;
+                       return NULL;
+               }
+       }
+
+       if (seg_is_thin_volume(lp) &&
+           ((lp->activate == CHANGE_AY) ||
+            (lp->activate == CHANGE_AE) ||
+            (lp->activate == CHANGE_ALY))) {
+               /* Ensure all stacked messages are submitted */
+               if (!(lvl = find_lv_in_vg(vg, lp->pool))) {
+                       log_error("Unable to find existing pool LV %s in VG %s.",
+                                 lp->pool, vg->name);
+                       return NULL;
                }
+               if (!update_pool_lv(lvl->lv, 1))
+                       return_NULL;
+       }
+
+       if (vg_is_clustered(vg) && segtype_is_raid(lp->segtype)) {
+               /*
+                * FIXME:
+                * We could allow a RAID LV to be created as long as it
+                * is activated exclusively.  Any subsequent activations
+                * would have to be enforced as exclusive also.
+                *
+                * For now, we disallow the existence of RAID LVs in a
+                * cluster VG
+                */
+               log_error("Unable to create a %s logical volume in a cluster.",
+                         lp->segtype->name);
+               return NULL;
        }
 
-       if (lp->mirrors > 1) {
+       if (segtype_is_mirrored(lp->segtype) || segtype_is_raid(lp->segtype)) {
                init_mirror_in_sync(lp->nosync);
 
                if (lp->nosync) {
-                       log_warn("WARNING: New mirror won't be synchronised. "
-                                 "Don't read what you didn't write!");
-                       status |= MIRROR_NOTSYNCED;
+                       log_warn("WARNING: New %s won't be synchronised. "
+                                "Don't read what you didn't write!",
+                                lp->segtype->name);
+                       status |= LV_NOTSYNCED;
                }
+
+               lp->region_size = adjusted_mirror_region_size(vg->extent_size,
+                                                             lp->extents,
+                                                             lp->region_size);
        }
 
-       if (!(lv = lv_create_empty(lp->lv_name ? lp->lv_name : "lvol%d", NULL,
+       if (!(lv = lv_create_empty(new_lv_name ? : "lvol%d", NULL,
                                   status, lp->alloc, vg)))
-               return_0;
+               return_NULL;
 
        if (lp->read_ahead != lv->read_ahead) {
                log_verbose("Setting read ahead sectors");
                lv->read_ahead = lp->read_ahead;
        }
 
-       if (lp->minor >= 0) {
+       if (!seg_is_thin_pool(lp) && lp->minor >= 0) {
                lv->major = lp->major;
                lv->minor = lp->minor;
                lv->status |= FIXED_MINOR;
@@ -3292,23 +4491,44 @@ int lv_create_single(struct volume_group *vg,
                            lv->minor);
        }
 
-       if (!dm_list_empty(&lp->tags))
-               dm_list_splice(&lv->tags, &lp->tags);
+       dm_list_splice(&lv->tags, &lp->tags);
 
-       if (!lv_extend(lv, lp->segtype, lp->stripes, lp->stripe_size,
-                      1, lp->extents, NULL, 0u, 0u, lp->pvh, lp->alloc))
-               return_0;
+       if (!lv_extend(lv, lp->segtype,
+                      lp->stripes, lp->stripe_size,
+                      lp->mirrors,
+                      seg_is_thin_pool(lp) ? lp->poolmetadataextents : lp->region_size,
+                      seg_is_thin_volume(lp) ? lp->voriginextents : lp->extents,
+                      seg_is_thin_volume(lp) ? (org ? org->name : lp->pool) : NULL, lp->pvh, lp->alloc))
+               return_NULL;
+
+       if (seg_is_thin_pool(lp)) {
+               first_seg(lv)->zero_new_blocks = lp->zero ? 1 : 0;
+               first_seg(lv)->chunk_size = lp->chunk_size;
+               first_seg(lv)->discards = lp->discards;
+               /* FIXME: use lowwatermark  via lvm.conf global for all thinpools ? */
+               first_seg(lv)->low_water_mark = 0;
+       } else if (seg_is_thin_volume(lp)) {
+               pool_lv = first_seg(lv)->pool_lv;
+
+               if (!(first_seg(lv)->device_id =
+                     get_free_pool_device_id(first_seg(pool_lv)))) {
+                       stack;
+                       goto revert_new_lv;
+               }
+
+               if (!attach_pool_message(first_seg(pool_lv),
+                                        DM_THIN_MESSAGE_CREATE_THIN, lv, 0, 0)) {
+                       stack;
+                       goto revert_new_lv;
+               }
+       }
 
-       if (lp->mirrors > 1) {
-               if (!lv_add_mirrors(cmd, lv, lp->mirrors - 1, lp->stripes,
-                                   lp->stripe_size,
-                                   adjusted_mirror_region_size(
-                                               vg->extent_size,
-                                               lv->le_count,
-                                               lp->region_size),
-                                   lp->log_count, lp->pvh, lp->alloc,
-                                   MIRROR_BY_LV |
-                                   (lp->nosync ? MIRROR_SKIP_INIT_SYNC : 0))) {
+       /* FIXME Log allocation and attachment should have happened inside lv_extend. */
+       if (lp->log_count &&
+           !seg_is_raid(first_seg(lv)) && seg_is_mirrored(first_seg(lv))) {
+               if (!add_mirror_log(cmd, lv, lp->log_count,
+                                   first_seg(lv)->region_size,
+                                   lp->pvh, lp->alloc)) {
                        stack;
                        goto revert_new_lv;
                }
@@ -3316,35 +4536,92 @@ int lv_create_single(struct volume_group *vg,
 
        /* store vg on disk(s) */
        if (!vg_write(vg) || !vg_commit(vg))
-               return_0;
+               return_NULL;
 
        backup(vg);
 
-       init_dmeventd_monitor(lp->activation_monitoring);
+       /*
+        * Check for autoactivation.
+        * If the LV passes the auto activation filter, activate
+        * it just as if CHANGE_AY was used, CHANGE_AN otherwise.
+        */
+       if (lp->activate == CHANGE_AAY)
+               lp->activate = lv_passes_auto_activation_filter(cmd, lv) ?
+                               CHANGE_ALY : CHANGE_ALN;
+
+       if (test_mode()) {
+               log_verbose("Test mode: Skipping activation and zeroing.");
+               goto out;
+       }
 
-       if (lp->snapshot) {
+       if (seg_is_thin(lp)) {
+               /* For snapshot, suspend active thin origin first */
+               if (org && lv_is_active(org)) {
+                       if (!pool_below_threshold(first_seg(first_seg(org)->pool_lv))) {
+                               log_error("Cannot create thin snapshot. Pool %s/%s is filled "
+                                         "over the autoextend threshold.",
+                                         org->vg->name, first_seg(org)->pool_lv->name);
+                               goto revert_new_lv;
+                       }
+                       if (!suspend_lv_origin(cmd, org)) {
+                               log_error("Failed to suspend thin snapshot origin %s/%s.",
+                                         org->vg->name, org->name);
+                               goto revert_new_lv;
+                       }
+                       if (!resume_lv_origin(cmd, org)) { /* deptree updates thin-pool */
+                               log_error("Failed to resume thin snapshot origin %s/%s.",
+                                         org->vg->name, org->name);
+                               goto revert_new_lv;
+                       }
+                       /* At this point remove pool messages, snapshot is active */
+                       if (!update_pool_lv(first_seg(org)->pool_lv, 0)) {
+                               stack;
+                               goto deactivate_and_revert_new_lv;
+                       }
+               }
+               if (((lp->activate == CHANGE_AY) ||
+                    (lp->activate == CHANGE_AE) ||
+                    (lp->activate == CHANGE_ALY))) {
+                       /* At this point send message to kernel thin mda */
+                       pool_lv = lv_is_thin_pool(lv) ? lv : first_seg(lv)->pool_lv;
+                       if (!update_pool_lv(pool_lv, 1)) {
+                               stack;
+                               goto deactivate_and_revert_new_lv;
+                       }
+                       if (!activate_lv_excl(cmd, lv)) {
+                               log_error("Aborting. Failed to activate thin %s.",
+                                         lv->name);
+                               goto deactivate_and_revert_new_lv;
+                       }
+               }
+       } else if (lp->snapshot) {
                if (!activate_lv_excl(cmd, lv)) {
                        log_error("Aborting. Failed to activate snapshot "
                                  "exception store.");
                        goto revert_new_lv;
                }
-       } else if (!activate_lv(cmd, lv)) {
+       } else if ((lp->activate == CHANGE_AY && !activate_lv(cmd, lv)) ||
+                  (lp->activate == CHANGE_AE && !activate_lv_excl(cmd, lv)) ||
+                  (lp->activate == CHANGE_ALY && !activate_lv_local(cmd, lv))) {
                log_error("Failed to activate new LV.");
                if (lp->zero)
                        goto deactivate_and_revert_new_lv;
-               return 0;
+               return NULL;
        }
 
-       if (!lp->zero && !lp->snapshot)
+       if (!seg_is_thin(lp) && !lp->zero && !lp->snapshot)
                log_warn("WARNING: \"%s\" not zeroed", lv->name);
-       else if (!set_lv(cmd, lv, UINT64_C(0), 0)) {
+       else if ((!seg_is_thin(lp) ||
+                 (lv_is_thin_volume(lv) &&
+                  !first_seg(first_seg(lv)->pool_lv)->zero_new_blocks)) &&
+                !set_lv(cmd, lv, UINT64_C(0), 0)) {
                log_error("Aborting. Failed to wipe %s.",
                          lp->snapshot ? "snapshot exception store" :
                                         "start of new LV");
                goto deactivate_and_revert_new_lv;
        }
 
-       if (lp->snapshot) {
+       if (lp->snapshot && !lp->thin) {
                /* Reset permission after zeroing */
                if (!(lp->permission & LVM_WRITE))
                        lv->status &= ~LVM_WRITE;
@@ -3353,7 +4630,7 @@ int lv_create_single(struct volume_group *vg,
                if (!origin_active && !deactivate_lv(cmd, lv)) {
                        log_error("Aborting. Couldn't deactivate snapshot "
                                  "COW area. Manual intervention required.");
-                       return 0;
+                       return NULL;
                }
 
                /* A virtual origin must be activated explicitly. */
@@ -3361,7 +4638,7 @@ int lv_create_single(struct volume_group *vg,
                    (!(org = _create_virtual_origin(cmd, vg, lv->name,
                                                    lp->permission,
                                                    lp->voriginextents)) ||
-                    !activate_lv(cmd, org))) {
+                    !activate_lv_excl(cmd, org))) {
                        log_error("Couldn't create virtual origin for LV %s",
                                  lv->name);
                        if (org && !lv_remove(org))
@@ -3379,39 +4656,33 @@ int lv_create_single(struct volume_group *vg,
 
                /* store vg on disk(s) */
                if (!vg_write(vg))
-                       return_0;
+                       return_NULL;
 
                if (!suspend_lv(cmd, org)) {
                        log_error("Failed to suspend origin %s", org->name);
                        vg_revert(vg);
-                       return 0;
+                       return NULL;
                }
 
                if (!vg_commit(vg))
-                       return_0;
+                       return_NULL;
 
                if (!resume_lv(cmd, org)) {
                        log_error("Problem reactivating origin %s", org->name);
-                       return 0;
+                       return NULL;
                }
        }
        /* FIXME out of sequence */
        backup(vg);
 
-       log_print("Logical volume \"%s\" created", lv->name);
-
-       /*
-        * FIXME: as a sanity check we could try reading the
-        * last block of the device ?
-        */
-
-       return 1;
+out:
+       return lv;
 
 deactivate_and_revert_new_lv:
        if (!deactivate_lv(cmd, lv)) {
                log_error("Unable to deactivate failed new LV. "
                          "Manual intervention required.");
-               return 0;
+               return NULL;
        }
 
 revert_new_lv:
@@ -3422,6 +4693,37 @@ revert_new_lv:
        else
                backup(vg);
 
-       return 0;
+       return NULL;
 }
 
+int lv_create_single(struct volume_group *vg,
+                    struct lvcreate_params *lp)
+{
+       struct logical_volume *lv;
+
+       /* Create thin pool first if necessary */
+       if (lp->create_thin_pool) {
+               if (!seg_is_thin_pool(lp) &&
+                   !(lp->segtype = get_segtype_from_string(vg->cmd, "thin-pool")))
+                       return_0;
+
+               if (!(lv = _lv_create_an_lv(vg, lp, lp->pool)))
+                       return_0;
+
+               if (!lp->thin)
+                       goto out;
+
+               lp->pool = lv->name;
+
+               if (!(lp->segtype = get_segtype_from_string(vg->cmd, "thin")))
+                       return_0;
+       }
+
+       if (!(lv = _lv_create_an_lv(vg, lp, lp->lv_name)))
+               return_0;
+
+out:
+       log_print_unless_silent("Logical volume \"%s\" created", lv->name);
+
+       return 1;
+}
index 3b8895c1463a45218bf1ec64ccba5ff58ee9b78e..f7c05a2a082454adf4e2a0004ba1662885963a20 100644 (file)
@@ -15,7 +15,6 @@
 
 #include "lib.h"
 #include "metadata.h"
-#include "toolcontext.h"
 #include "lv_alloc.h"
 #include "pv_alloc.h"
 #include "str_list.h"
@@ -75,6 +74,40 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
        struct replicator_site *rsite;
        struct replicator_device *rdev;
 
+       /* Check LV flags match first segment type */
+       if (complete_vg) {
+               if (lv_is_thin_volume(lv) &&
+                   (!(seg2 = first_seg(lv)) || !seg_is_thin_volume(seg2))) {
+                       log_error("LV %s is thin volume without first thin volume segment",
+                                 lv->name);
+                       inc_error_count;
+               }
+
+               if (lv_is_thin_pool(lv) &&
+                   (!(seg2 = first_seg(lv)) || !seg_is_thin_pool(seg2))) {
+                       log_error("LV %s is thin pool without first thin pool segment",
+                                 lv->name);
+                       inc_error_count;
+               }
+
+               if (lv_is_thin_pool_data(lv) &&
+                   (!(seg2 = first_seg(lv)) || !(seg2 = find_pool_seg(seg2)) ||
+                    seg2->area_count != 1 || seg_type(seg2, 0) != AREA_LV ||
+                    seg_lv(seg2, 0) != lv)) {
+                       log_error("LV %s: segment 1 pool data LV does not point back to same LV",
+                                 lv->name);
+                       inc_error_count;
+               }
+
+               if (lv_is_thin_pool_metadata(lv) &&
+                   (!(seg2 = first_seg(lv)) || !(seg2 = find_pool_seg(seg2)) ||
+                    seg2->metadata_lv != lv)) {
+                       log_error("LV %s: segment 1 pool metadata LV does not point back to same LV",
+                                 lv->name);
+                       inc_error_count;
+               }
+       }
+
        dm_list_iterate_items(seg, &lv->segments) {
                seg_count++;
                if (seg->le != le) {
@@ -94,18 +127,22 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
                        inc_error_count;
                }
 
-               if (complete_vg && seg->log_lv) {
-                       if (!seg_is_mirrored(seg)) {
-                               log_error("LV %s: segment %u has log LV but "
-                                         "is not mirrored",
-                                         lv->name, seg_count);
-                               inc_error_count;
-                       }
+               if (complete_vg && seg->log_lv &&
+                   !seg_is_mirrored(seg) && !(seg->status & RAID_IMAGE)) {
+                       log_error("LV %s: segment %u log LV %s is not a "
+                                 "mirror log or a RAID image",
+                                 lv->name, seg_count, seg->log_lv->name);
+                       inc_error_count;
+               }
 
+               /*
+                * Check mirror log - which is attached to the mirrored seg
+                */
+               if (complete_vg && seg->log_lv && seg_is_mirrored(seg)) {
                        if (!(seg->log_lv->status & MIRROR_LOG)) {
                                log_error("LV %s: segment %u log LV %s is not "
                                          "a mirror log",
-                                          lv->name, seg_count, seg->log_lv->name);
+                                         lv->name, seg_count, seg->log_lv->name);
                                inc_error_count;
                        }
 
@@ -113,7 +150,7 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
                            find_mirror_seg(seg2) != seg) {
                                log_error("LV %s: segment %u log LV does not "
                                          "point back to mirror segment",
-                                          lv->name, seg_count);
+                                         lv->name, seg_count);
                                inc_error_count;
                        }
                }
@@ -128,6 +165,93 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
                        }
                }
 
+               /* Check the various thin segment types */
+               if (complete_vg) {
+                       if (seg_is_thin_pool(seg)) {
+                               if (!lv_is_thin_pool(lv)) {
+                                       log_error("LV %s is missing thin pool flag for segment %u",
+                                                 lv->name, seg_count);
+                                       inc_error_count;
+                               }
+
+                               if (lv_is_thin_volume(lv)) {
+                                       log_error("LV %s is a thin volume that must not contain thin pool segment %u",
+                                                 lv->name, seg_count);
+                                       inc_error_count;
+                               }
+
+                               if (seg->area_count != 1 || seg_type(seg, 0) != AREA_LV) {
+                                       log_error("LV %s: thin pool segment %u is missing a pool data LV",
+                                                 lv->name, seg_count);
+                                       inc_error_count;
+                               } else if (!(seg2 = first_seg(seg_lv(seg, 0))) || find_pool_seg(seg2) != seg) {
+                                       log_error("LV %s: thin pool segment %u data LV does not refer back to pool LV",
+                                                 lv->name, seg_count);
+                                       inc_error_count;
+                               }
+
+                               if (!seg->metadata_lv) {
+                                       log_error("LV %s: thin pool segment %u is missing a pool metadata LV",
+                                                 lv->name, seg_count);
+                                       inc_error_count;
+                               } else if (!(seg2 = first_seg(seg->metadata_lv)) ||
+                                          find_pool_seg(seg2) != seg) {
+                                       log_error("LV %s: thin pool segment %u metadata LV does not refer back to pool LV",
+                                                 lv->name, seg_count);
+                                       inc_error_count;
+                               }
+
+                               if (seg->chunk_size < DM_THIN_MIN_DATA_BLOCK_SIZE ||
+                                   seg->chunk_size > DM_THIN_MAX_DATA_BLOCK_SIZE) {
+                                       log_error("LV %s: thin pool segment %u has chunk size %u out of range.",
+                                                 lv->name, seg_count, seg->chunk_size);
+                                       inc_error_count;
+                               }
+                       } else {
+                               if (seg->metadata_lv) {
+                                       log_error("LV %s: segment %u must not have thin pool metadata LV set",
+                                                 lv->name, seg_count);
+                                       inc_error_count;
+                               }
+                       }
+
+                       if (seg_is_thin_volume(seg)) {
+                               if (!lv_is_thin_volume(lv)) {
+                                       log_error("LV %s is missing thin volume flag for segment %u",
+                                                 lv->name, seg_count);
+                                       inc_error_count;
+                               }
+
+                               if (lv_is_thin_pool(lv)) {
+                                       log_error("LV %s is a thin pool that must not contain thin volume segment %u",
+                                                 lv->name, seg_count);
+                                       inc_error_count;
+                               }
+
+                               if (!seg->pool_lv) {
+                                       log_error("LV %s: segment %u is missing thin pool LV",
+                                                 lv->name, seg_count);
+                                       inc_error_count;
+                               } else if (!lv_is_thin_pool(seg->pool_lv)) {
+                                       log_error("LV %s: thin volume segment %u pool LV is not flagged as a pool LV",
+                                                 lv->name, seg_count);
+                                       inc_error_count;
+                               }
+
+                               if (seg->device_id > DM_THIN_MAX_DEVICE_ID) {
+                                       log_error("LV %s: thin volume segment %u has too large device id %u",
+                                                 lv->name, seg_count, seg->device_id);
+                                       inc_error_count;
+                               }
+                       } else {
+                               if (seg->pool_lv) {
+                                       log_error("LV %s: segment %u must not have thin pool LV set",
+                                                 lv->name, seg_count);
+                                       inc_error_count;
+                               }
+                       }
+               }
+
                if (seg_is_snapshot(seg)) {
                        if (seg->cow && seg->cow == seg->origin) {
                                log_error("LV %s: segment %u has same LV %s for "
@@ -189,8 +313,9 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
                                dm_list_iterate_items(sl, &seg_lv(seg, s)->segs_using_this_lv)
                                        if (sl->seg == seg)
                                                seg_found++;
+
                                if (!seg_found) {
-                                       log_error("LV %s segment %d uses LV %s,"
+                                       log_error("LV %s segment %u uses LV %s,"
                                                  " but missing ptr from %s to %s",
                                                  lv->name, seg_count,
                                                  seg_lv(seg, s)->name,
@@ -198,12 +323,23 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
                                        inc_error_count;
                                } else if (seg_found > 1) {
                                        log_error("LV %s has duplicated links "
-                                                 "to LV %s segment %d",
+                                                 "to LV %s segment %u",
                                                  seg_lv(seg, s)->name,
                                                  lv->name, seg_count);
                                        inc_error_count;
                                }
                        }
+
+                       if (complete_vg &&
+                           seg_is_mirrored(seg) && !seg_is_raid(seg) &&
+                           seg_type(seg, s) == AREA_LV &&
+                           seg_lv(seg, s)->le_count != seg->area_len) {
+                               log_error("LV %s: mirrored LV segment %u has "
+                                         "wrong size %u (should be %u).",
+                                         lv->name, s, seg_lv(seg, s)->le_count,
+                                         seg->area_len);
+                               inc_error_count;
+                       }
                }
 
                le += seg->len;
@@ -217,6 +353,8 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
                                continue;
                        if (lv == seg_lv(seg, s))
                                seg_found++;
+                       if (seg_is_raid(seg) && (lv == seg_metalv(seg, s)))
+                               seg_found++;
                }
                if (seg_is_replicator_dev(seg)) {
                        dm_list_iterate_items(rsite, &seg->replicator->rsites) {
@@ -232,6 +370,10 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
                                seg_found++;
                if (seg->log_lv == lv)
                        seg_found++;
+               if (seg->metadata_lv == lv || seg->pool_lv == lv)
+                       seg_found++;
+               if (seg_is_thin_volume(seg) && seg->origin == lv)
+                       seg_found++;
                if (!seg_found) {
                        log_error("LV %s is used by LV %s:%" PRIu32 "-%" PRIu32
                                  ", but missing ptr from %s to %s",
@@ -240,9 +382,9 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
                                  seg->lv->name, lv->name);
                        inc_error_count;
                } else if (seg_found != sl->count) {
-                       log_error("Reference count mismatch: LV %s has %d "
+                       log_error("Reference count mismatch: LV %s has %u "
                                  "links to LV %s:%" PRIu32 "-%" PRIu32
-                                 ", which has %d links",
+                                 ", which has %u links",
                                  lv->name, sl->count, seg->lv->name, seg->le,
                                  seg->le + seg->len - 1, seg_found);
                        inc_error_count;
@@ -287,15 +429,16 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
 
        if (!seg_can_split(seg)) {
                log_error("Unable to split the %s segment at LE %" PRIu32
-                         " in LV %s", seg->segtype->name, le, lv->name);
+                         " in LV %s", seg->segtype->ops->name(seg),
+                         le, lv->name);
                return 0;
        }
 
        /* Clone the existing segment */
-       if (!(split_seg = alloc_lv_segment(lv->vg->vgmem, seg->segtype,
+       if (!(split_seg = alloc_lv_segment(seg->segtype,
                                           seg->lv, seg->le, seg->len,
                                           seg->status, seg->stripe_size,
-                                          seg->log_lv,
+                                          seg->log_lv, seg->pool_lv,
                                           seg->area_count, seg->area_len,
                                           seg->chunk_size, seg->region_size,
                                           seg->extents_copied, seg->pvmove_source_seg))) {
index 6994e0c1f3e4338fdcd749ff633de45eeb70f0a9..d149f953f62436953aca3d8ef2a9ead3b6fbb3b1 100644 (file)
@@ -33,8 +33,8 @@
 #define STRIPE_SIZE_MIN ( (unsigned) lvm_getpagesize() >> SECTOR_SHIFT)        /* PAGESIZE in sectors */
 #define STRIPE_SIZE_MAX ( 512L * 1024L >> SECTOR_SHIFT)        /* 512 KB in sectors */
 #define STRIPE_SIZE_LIMIT ((UINT_MAX >> 2) + 1)
-#define PV_MIN_SIZE ( 512L * 1024L >> SECTOR_SHIFT)    /* 512 KB in sectors */
 #define MAX_RESTRICTED_LVS 255 /* Used by FMT_RESTRICTED_LVIDS */
+#define MAX_EXTENT_SIZE ((uint32_t) -1)
 
 /* Layer suffix */
 #define MIRROR_SYNC_LAYER "_mimagetmp"
 /* Various flags */
 /* Note that the bits no longer necessarily correspond to LVM1 disk format */
 
-#define PARTIAL_VG             0x00000001U     /* VG */
-#define EXPORTED_VG            0x00000002U     /* VG PV */
-#define RESIZEABLE_VG          0x00000004U     /* VG */
+#define PARTIAL_VG             UINT64_C(0x00000001)    /* VG */
+#define EXPORTED_VG            UINT64_C(0x00000002)    /* VG PV */
+#define RESIZEABLE_VG          UINT64_C(0x00000004)    /* VG */
 
 /* May any free extents on this PV be used or must they be left free? */
-#define ALLOCATABLE_PV                 0x00000008U     /* PV */
+#define ALLOCATABLE_PV         UINT64_C(0x00000008)    /* PV */
 
-//#define SPINDOWN_LV                  0x00000010U     /* LV */
-//#define BADBLOCK_ON          0x00000020U     /* LV */
-#define VISIBLE_LV             0x00000040U     /* LV */
-#define FIXED_MINOR            0x00000080U     /* LV */
+//#define SPINDOWN_LV          UINT64_C(0x00000010)    /* LV */
+//#define BADBLOCK_ON          UINT64_C(0x00000020)    /* LV */
+#define VISIBLE_LV             UINT64_C(0x00000040)    /* LV */
+#define FIXED_MINOR            UINT64_C(0x00000080)    /* LV */
 /* FIXME Remove when metadata restructuring is completed */
-#define SNAPSHOT               0x00001000U     /* LV - internal use only */
-#define PVMOVE                 0x00002000U     /* VG LV SEG */
-#define LOCKED                 0x00004000U     /* LV */
-#define MIRRORED               0x00008000U     /* LV - internal use only */
-//#define VIRTUAL                      0x00010000U     /* LV - internal use only */
-#define MIRROR_LOG             0x00020000U     /* LV */
-#define MIRROR_IMAGE           0x00040000U     /* LV */
-#define MIRROR_NOTSYNCED       0x00080000U     /* LV */
-//#define ACTIVATE_EXCL                0x00100000U     /* LV - internal use only */
-//#define PRECOMMITTED         0x00200000U     /* VG - internal use only */
-#define CONVERTING             0x00400000U     /* LV */
-
-#define MISSING_PV              0x00800000U    /* PV */
-#define PARTIAL_LV              0x01000000U    /* LV - derived flag, not
-                                                  written out in metadata*/
-
-//#define POSTORDER_FLAG       0x02000000U /* Not real flags, reserved for
-//#define POSTORDER_OPEN_FLAG  0x04000000U    temporary use inside vg_read_internal. */
-//#define VIRTUAL_ORIGIN       0x08000000U     /* LV - internal use only */
-
-#define MERGING                        0x10000000U     /* LV SEG */
-
-#define REPLICATOR             0x20000000U     /* LV -internal use only for replicator */
-#define REPLICATOR_LOG         0x40000000U     /* LV -internal use only for replicator-dev */
-
-#define LVM_READ               0x00000100U     /* LV VG */
-#define LVM_WRITE              0x00000200U     /* LV VG */
-#define CLUSTERED              0x00000400U     /* VG */
-//#define SHARED               0x00000800U     /* VG */
+#define SNAPSHOT               UINT64_C(0x00001000)    /* LV - internal use only */
+#define PVMOVE                 UINT64_C(0x00002000)    /* VG LV SEG */
+#define LOCKED                 UINT64_C(0x00004000)    /* LV */
+#define MIRRORED               UINT64_C(0x00008000)    /* LV - internal use only */
+//#define VIRTUAL              UINT64_C(0x00010000)    /* LV - internal use only */
+#define MIRROR_LOG             UINT64_C(0x00020000)    /* LV */
+#define MIRROR_IMAGE           UINT64_C(0x00040000)    /* LV */
+
+#define LV_NOTSYNCED           UINT64_C(0x00080000)    /* LV */
+#define LV_REBUILD             UINT64_C(0x00100000)    /* LV */
+//#define PRECOMMITTED         UINT64_C(0x00200000)    /* VG - internal use only */
+#define CONVERTING             UINT64_C(0x00400000)    /* LV */
+
+#define MISSING_PV             UINT64_C(0x00800000)    /* PV */
+#define PARTIAL_LV             UINT64_C(0x01000000)    /* LV - derived flag, not
+                                                          written out in metadata*/
+
+//#define POSTORDER_FLAG       UINT64_C(0x02000000) /* Not real flags, reserved for
+//#define POSTORDER_OPEN_FLAG  UINT64_C(0x04000000)    temporary use inside vg_read_internal. */
+//#define VIRTUAL_ORIGIN       UINT64_C(0x08000000)    /* LV - internal use only */
+
+#define MERGING                        UINT64_C(0x10000000)    /* LV SEG */
+
+#define REPLICATOR             UINT64_C(0x20000000)    /* LV -internal use only for replicator */
+#define REPLICATOR_LOG         UINT64_C(0x40000000)    /* LV -internal use only for replicator-dev */
+#define UNLABELLED_PV          UINT64_C(0x80000000)    /* PV -this PV had no label written yet */
+
+#define RAID                   UINT64_C(0x0000000100000000)    /* LV */
+#define RAID_META              UINT64_C(0x0000000200000000)    /* LV */
+#define RAID_IMAGE             UINT64_C(0x0000000400000000)    /* LV */
+
+#define THIN_VOLUME            UINT64_C(0x0000001000000000)    /* LV */
+#define THIN_POOL              UINT64_C(0x0000002000000000)    /* LV */
+#define THIN_POOL_DATA         UINT64_C(0x0000004000000000)    /* LV */
+#define THIN_POOL_METADATA     UINT64_C(0x0000008000000000)    /* LV */
+
+#define LVM_READ               UINT64_C(0x00000100)    /* LV, VG */
+#define LVM_WRITE              UINT64_C(0x00000200)    /* LV, VG */
+
+#define CLUSTERED              UINT64_C(0x00000400)    /* VG */
+//#define SHARED               UINT64_C(0x00000800)    /* VG */
 
 /* Format features flags */
 #define FMT_SEGMENTS           0x00000001U     /* Arbitrary segment params? */
 /* vg_read and vg_read_for_update flags */
 #define READ_ALLOW_INCONSISTENT        0x00010000U
 #define READ_ALLOW_EXPORTED    0x00020000U
-#define READ_WITHOUT_LOCK       0x00040000U
+#define READ_WITHOUT_LOCK      0x00040000U
 
 /* A meta-flag, useful with toollib for_each_* functions. */
-#define READ_FOR_UPDATE        0x00100000U
+#define READ_FOR_UPDATE                0x00100000U
 
 /* vg's "read_status" field */
 #define FAILED_INCONSISTENT    0x00000001U
 #define VGMETADATACOPIES_ALL UINT32_MAX
 #define VGMETADATACOPIES_UNMANAGED 0
 
+#define lv_is_thin_volume(lv)  ((lv)->status & THIN_VOLUME ? 1 : 0)
+#define lv_is_thin_pool(lv)    ((lv)->status & THIN_POOL ? 1 : 0)
+#define lv_is_used_thin_pool(lv)       (lv_is_thin_pool(lv) && !dm_list_empty(&(lv)->segs_using_this_lv))
+#define lv_is_thin_pool_data(lv)       ((lv)->status & THIN_POOL_DATA ? 1 : 0)
+#define lv_is_thin_pool_metadata(lv)   ((lv)->status & THIN_POOL_METADATA ? 1 : 0)
+#define lv_is_mirrored(lv)     ((lv)->status & MIRRORED ? 1 : 0)
+#define lv_is_rlog(lv)         ((lv)->status & REPLICATOR_LOG ? 1 : 0)
+
+#define lv_is_thin_type(lv)    ((lv)->status & (THIN_POOL | THIN_VOLUME | THIN_POOL_DATA | THIN_POOL_METADATA) ? 1 : 0)
+#define lv_is_mirror_type(lv)  ((lv)->status & (MIRROR_LOG | MIRROR_IMAGE | MIRRORED | PVMOVE) ? 1 : 0)
+#define lv_is_raid_type(lv)    ((lv)->status & (RAID | RAID_IMAGE | RAID_META))
+
+#define lv_is_virtual(lv)      ((lv)->status & VIRTUAL)
+
 /* Ordered list - see lv_manip.c */
 typedef enum {
        AREA_UNASSIGNED,
@@ -140,6 +166,12 @@ typedef enum {
        DONT_PROMPT_OVERRIDE = 2 /* Skip prompt + override a second condition */
 } force_t;
 
+typedef enum {
+       THIN_DISCARDS_IGNORE,
+       THIN_DISCARDS_NO_PASSDOWN,
+       THIN_DISCARDS_PASSDOWN,
+} thin_discards_t;
+
 struct cmd_context;
 struct format_handler;
 struct labeller;
@@ -148,10 +180,12 @@ struct format_type {
        struct dm_list list;
        struct cmd_context *cmd;
        struct format_handler *ops;
+       struct dm_list mda_ops; /* List of permissible mda ops. */
        struct labeller *labeller;
        const char *name;
        const char *alias;
        const char *orphan_vg_name;
+       struct volume_group *orphan_vg; /* Only one ever exists. */
        uint32_t features;
        void *library;
        void *private;
@@ -171,16 +205,46 @@ struct pv_segment {
 
 #define pvseg_is_allocated(pvseg) ((pvseg)->lvseg)
 
+/*
+ * Properties of each format instance type.
+ * The primary role of the format_instance is to temporarily store metadata
+ * area information we are working with.
+ */
+
+/* Include any existing PV ("on-disk") mdas during format_instance initialisation. */
+#define FMT_INSTANCE_MDAS              0x00000002U
+
+/*
+ * Include any auxiliary mdas during format_instance intialisation.
+ * Currently, this includes metadata areas as defined by
+ * metadata/dirs and metadata/raws setting.
+ */
+#define FMT_INSTANCE_AUX_MDAS          0x00000004U
+
+/*
+ * Include any other format-specific mdas during format_instance initialisation.
+ * For example metadata areas used during backup/restore/archive handling.
+ */
+#define FMT_INSTANCE_PRIVATE_MDAS      0x00000008U
+
 struct format_instance {
+       unsigned ref_count;     /* Refs to this fid from VG and PV structs */
+       struct dm_pool *mem;
+
+       uint32_t type;
        const struct format_type *fmt;
+
        /*
         * Each mda in a vg is on exactly one of the below lists.
         * MDAs on the 'in_use' list will be read from / written to
         * disk, while MDAs on the 'ignored' list will not be read
         * or written to.
         */
+       /* FIXME: Try to use the index only. Remove these lists. */
        struct dm_list metadata_areas_in_use;
        struct dm_list metadata_areas_ignored;
+       struct dm_hash_table *metadata_areas_index;
+
        void *private;
 };
 
@@ -198,6 +262,15 @@ struct lv_segment_area {
        } u;
 };
 
+struct lv_thin_message {
+       struct dm_list list;            /* Chained list of messages */
+       dm_thin_message_t type;         /* Use dm thin message datatype */
+       union {
+               struct logical_volume *lv; /* For: create_thin, create_snap, trim */
+               uint32_t delete_id;     /* For delete, needs device_id */
+       } u;
+};
+
 struct segment_type;
 
 /* List with vg_name, vgid and flags */
@@ -222,9 +295,9 @@ struct replicator_site {
 
        struct logical_volume *replicator; /* Reference to replicator */
 
-       const char *name;               /* Site name */
+       const char *name;               /* Site name */
        const char *vg_name;            /* VG name */
-       struct volume_group *vg;        /* resolved vg  (activate/deactive) */
+       struct volume_group *vg;        /* resolved vg  (activate/deactive) */
        unsigned site_index;
        replicator_state_t state;       /* Active or pasive state of site */
        dm_replicator_mode_t op_mode;   /* Operation mode sync or async fail|warn|drop|stall */
@@ -258,11 +331,12 @@ struct lv_segment {
        uint64_t status;
 
        /* FIXME Fields depend on segment type */
-       uint32_t stripe_size;
+       uint32_t stripe_size;   /* For stripe and RAID - in sectors */
        uint32_t area_count;
        uint32_t area_len;
-       uint32_t chunk_size;    /* For snapshots - in sectors */
-       struct logical_volume *origin;
+       uint32_t chunk_size;    /* For snapshots/thin_pool.  In sectors. */
+                               /* For thin_pool, 128..2097152. */
+       struct logical_volume *origin;  /* snap and thin */
        struct logical_volume *cow;
        struct dm_list origin_list;
        uint32_t region_size;   /* For mirrors, replicators - in sectors */
@@ -274,6 +348,15 @@ struct lv_segment {
        struct dm_list tags;
 
        struct lv_segment_area *areas;
+       struct lv_segment_area *meta_areas;     /* For RAID */
+       struct logical_volume *metadata_lv;     /* For thin_pool */
+       uint64_t transaction_id;                /* For thin_pool, thin */
+       uint64_t low_water_mark;                /* For thin_pool */
+       unsigned zero_new_blocks;               /* For thin_pool */
+       thin_discards_t discards;               /* For thin_pool */
+       struct dm_list thin_messages;           /* For thin_pool */
+       struct logical_volume *pool_lv;         /* For thin */
+       uint32_t device_id;                     /* For thin, 24bit */
 
        struct logical_volume *replicator;/* For replicator-devs - link to replicator LV */
        struct logical_volume *rlog_lv; /* For replicators */
@@ -285,6 +368,8 @@ struct lv_segment {
 #define seg_type(seg, s)       (seg)->areas[(s)].type
 #define seg_pv(seg, s)         (seg)->areas[(s)].u.pv.pvseg->pv
 #define seg_lv(seg, s)         (seg)->areas[(s)].u.lv.lv
+#define seg_metalv(seg, s)     (seg)->meta_areas[(s)].u.lv.lv
+#define seg_metatype(seg, s)   (seg)->meta_areas[(s)].type
 
 struct pe_range {
        struct dm_list list;
@@ -325,7 +410,8 @@ struct pvcreate_params {
 
 struct physical_volume *pvcreate_single(struct cmd_context *cmd,
                                        const char *pv_name,
-                                       struct pvcreate_params *pp);
+                                       struct pvcreate_params *pp,
+                                       int write_now);
 void pvcreate_params_set_defaults(struct pvcreate_params *pp);
 
 /*
@@ -333,12 +419,12 @@ void pvcreate_params_set_defaults(struct pvcreate_params *pp);
 */
 int vg_write(struct volume_group *vg);
 int vg_commit(struct volume_group *vg);
-int vg_revert(struct volume_group *vg);
+void vg_revert(struct volume_group *vg);
 struct volume_group *vg_read_internal(struct cmd_context *cmd, const char *vg_name,
-                            const char *vgid, int warnings, int *consistent);
+                                     const char *vgid, int warnings, int *consistent);
 struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
-                               struct dm_list *mdas, uint64_t *label_sector,
-                               int warnings, int scan_label_only);
+                               int warnings,
+                               int scan_label_only);
 struct dm_list *get_pvs(struct cmd_context *cmd);
 
 /*
@@ -353,8 +439,7 @@ struct dm_list *get_vgnames(struct cmd_context *cmd, int include_internal);
 struct dm_list *get_vgids(struct cmd_context *cmd, int include_internal);
 int scan_vgs_for_pvs(struct cmd_context *cmd, int warnings);
 
-int pv_write(struct cmd_context *cmd, struct physical_volume *pv,
-            struct dm_list *mdas, int64_t label_sector);
+int pv_write(struct cmd_context *cmd, struct physical_volume *pv, int allow_non_orphan);
 int move_pv(struct volume_group *vg_from, struct volume_group *vg_to,
            const char *pv_name);
 int move_pvs_used_by_lv(struct volume_group *vg_from,
@@ -362,6 +447,7 @@ int move_pvs_used_by_lv(struct volume_group *vg_from,
                        const char *lv_name);
 int is_global_vg(const char *vg_name);
 int is_orphan_vg(const char *vg_name);
+int is_real_vg(const char *vg_name);
 int vg_missing_pv_count(const struct volume_group *vg);
 int vgs_are_compatible(struct cmd_context *cmd,
                       struct volume_group *vg_from,
@@ -372,9 +458,9 @@ uint32_t vg_lock_newname(struct cmd_context *cmd, const char *vgname);
  * Return a handle to VG metadata.
  */
 struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
-              const char *vgid, uint32_t flags);
+                            const char *vgid, uint32_t flags);
 struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_name,
-                         const char *vgid, uint32_t flags);
+                        const char *vgid, uint32_t flags);
 
 /* 
  * Test validity of a VG handle.
@@ -392,11 +478,12 @@ struct physical_volume *pv_create(const struct cmd_context *cmd,
                                  uint64_t pe_start,
                                  uint32_t existing_extent_count,
                                  uint32_t existing_extent_size,
-                                 int pvmetadatacopies, uint64_t pvmetadatasize,
-                                 unsigned metadataignore,
-                                 struct dm_list *mdas);
+                                 uint64_t label_sector,
+                                 unsigned pvmetadatacopies,
+                                 uint64_t pvmetadatasize,
+                                 unsigned metadataignore);
 int pv_resize(struct physical_volume *pv, struct volume_group *vg,
-             uint32_t new_pe_count);
+             uint64_t size);
 int pv_analyze(struct cmd_context *cmd, const char *pv_name,
               uint64_t label_sector);
 
@@ -410,9 +497,9 @@ void vg_remove_pvs(struct volume_group *vg);
 int vg_remove(struct volume_group *vg);
 int vg_rename(struct cmd_context *cmd, struct volume_group *vg,
              const char *new_name);
-int vg_extend(struct volume_group *vg, int pv_count, char **pv_names,
+int vg_extend(struct volume_group *vg, int pv_count, const char *const *pv_names,
              struct pvcreate_params *pp);
-int vg_reduce(struct volume_group *vg, char *pv_name);
+int vg_reduce(struct volume_group *vg, const char *pv_name);
 int vg_change_tag(struct volume_group *vg, const char *tag, int add_tag);
 int vg_split_mdas(struct cmd_context *cmd, struct volume_group *vg_from,
                  struct volume_group *vg_to);
@@ -424,11 +511,13 @@ void del_pvl_from_vgs(struct volume_group *vg, struct pv_list *pvl);
 int remove_lvs_in_vg(struct cmd_context *cmd,
                     struct volume_group *vg,
                     force_t force);
+
 /*
- * free_vg() must be called on every struct volume_group allocated
- * by vg_create() or vg_read_internal() to free it when no longer required.
+ * free_pv_fid() must be called on every struct physical_volume allocated
+ * by pv_create, pv_read, find_pv_by_name or pv_by_path to free it when
+ * no longer required.
  */
-void free_vg(struct volume_group *vg);
+void free_pv_fid(struct physical_volume *pv);
 
 /* Manipulate LVs */
 struct logical_volume *lv_create_empty(const char *name,
@@ -439,7 +528,7 @@ struct logical_volume *lv_create_empty(const char *name,
 
 /* Write out LV contents */
 int set_lv(struct cmd_context *cmd, struct logical_volume *lv,
-           uint64_t sectors, int value);
+          uint64_t sectors, int value);
 
 int lv_change_tag(struct logical_volume *lv, const char *tag, int add_tag);
 
@@ -456,10 +545,9 @@ int replace_lv_with_error_segment(struct logical_volume *lv);
 int lv_extend(struct logical_volume *lv,
              const struct segment_type *segtype,
              uint32_t stripes, uint32_t stripe_size,
-             uint32_t mirrors, uint32_t extents,
-             struct physical_volume *mirrored_pv, uint32_t mirrored_pe,
-             uint64_t status, struct dm_list *allocatable_pvs,
-             alloc_policy_t alloc);
+             uint32_t mirrors, uint32_t region_size,
+             uint32_t extents, const char *thin_pool_name,
+             struct dm_list *allocatable_pvs, alloc_policy_t alloc);
 
 /* lv must be part of lv->vg->lvs */
 int lv_remove(struct logical_volume *lv);
@@ -472,22 +560,44 @@ int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume *
 
 int lv_rename(struct cmd_context *cmd, struct logical_volume *lv,
              const char *new_name);
+int lv_rename_update(struct cmd_context *cmd, struct logical_volume *lv,
+                    const char *new_name, int update_mda);
 
 uint64_t extents_from_size(struct cmd_context *cmd, uint64_t size,
                           uint32_t extent_size);
 
+int update_pool_lv(struct logical_volume *lv, int activate);
+int get_pool_discards(const char *str, thin_discards_t *discards);
+const char *get_pool_discards_name(thin_discards_t discards);
+
+/*
+ * Activation options
+ */
+typedef enum activation_change {
+       CHANGE_AY = 0,  /* activate */
+       CHANGE_AN = 1,  /* deactivate */
+       CHANGE_AE = 2,  /* activate exclusively */
+       CHANGE_ALY = 3, /* activate locally */
+       CHANGE_ALN = 4, /* deactivate locally */
+       CHANGE_AAY = 5  /* automatic activation */
+} activation_change_t;
+
 /* FIXME: refactor and reduce the size of this struct! */
 struct lvcreate_params {
        /* flags */
        int snapshot; /* snap */
+       int thin; /* thin */
+       int create_thin_pool; /* thin */
        int zero; /* all */
        int major; /* all */
        int minor; /* all */
        int log_count; /* mirror */
        int nosync; /* mirror */
-       int activation_monitoring; /* all */
+       activation_change_t activate; /* non-snapshot, non-mirror */
+       thin_discards_t discards;     /* thin */
 
-       char *origin; /* snap */
+       const char *origin; /* snap */
+       const char *pool;   /* thin */
        const char *vg_name; /* all */
        const char *lv_name; /* all */
 
@@ -504,6 +614,8 @@ struct lvcreate_params {
        uint32_t extents; /* all */
        uint32_t voriginextents; /* snapshot */
        uint64_t voriginsize; /* snapshot */
+       uint32_t poolmetadataextents; /* thin pool */
+       uint64_t poolmetadatasize; /* thin pool */
        struct dm_list *pvh; /* all */
 
        uint32_t permission; /* all */
@@ -564,6 +676,7 @@ const char *find_vgname_from_pvid(struct cmd_context *cmd,
                                  const char *pvid);
 /* Find LV segment containing given LE */
 struct lv_segment *first_seg(const struct logical_volume *lv);
+struct lv_segment *last_seg(const struct logical_volume *lv);
 
 
 /*
@@ -626,10 +739,9 @@ int lv_remove_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
 
 int is_temporary_mirror_layer(const struct logical_volume *lv);
 struct logical_volume * find_temporary_mirror(const struct logical_volume *lv);
-int lv_is_mirrored(const struct logical_volume *lv);
 uint32_t lv_mirror_count(const struct logical_volume *lv);
 uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
-                                    uint32_t region_size);
+                                   uint32_t region_size);
 int remove_mirrors_from_segments(struct logical_volume *lv,
                                 uint32_t new_mirrors, uint64_t status_mask);
 int add_mirrors_to_segments(struct cmd_context *cmd, struct logical_volume *lv,
@@ -651,8 +763,11 @@ int add_mirror_log(struct cmd_context *cmd, struct logical_volume *lv,
                   uint32_t log_count, uint32_t region_size,
                   struct dm_list *allocatable_pvs, alloc_policy_t alloc);
 
+#if 0
+/* FIXME: reconfigure_mirror_images: remove this code? */
 int reconfigure_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
                              struct dm_list *removable_pvs, unsigned remove_log);
+#endif
 int collapse_mirrored_lv(struct logical_volume *lv);
 int shift_mirror_images(struct lv_segment *mirrored_seg, unsigned mimage);
 
@@ -672,10 +787,27 @@ int lv_is_active_replicator_dev(const struct logical_volume *lv);
 int lv_is_replicator(const struct logical_volume *lv);
 int lv_is_replicator_dev(const struct logical_volume *lv);
 int lv_is_rimage(const struct logical_volume *lv);
-int lv_is_rlog(const struct logical_volume *lv);
 int lv_is_slog(const struct logical_volume *lv);
 struct logical_volume *first_replicator_dev(const struct logical_volume *lv);
 /* --  metadata/replicator_manip.c */
+
+/* ++  metadata/raid_manip.c */
+int lv_is_raid_with_tracking(const struct logical_volume *lv);
+uint32_t lv_raid_image_count(const struct logical_volume *lv);
+int lv_raid_change_image_count(struct logical_volume *lv,
+                              uint32_t new_count, struct dm_list *pvs);
+int lv_raid_split(struct logical_volume *lv, const char *split_name,
+                 uint32_t new_count, struct dm_list *splittable_pvs);
+int lv_raid_split_and_track(struct logical_volume *lv,
+                           struct dm_list *splittable_pvs);
+int lv_raid_merge(struct logical_volume *lv);
+int lv_raid_reshape(struct logical_volume *lv,
+                   const struct segment_type *new_segtype);
+int lv_raid_replace(struct logical_volume *lv, struct dm_list *remove_pvs,
+                   struct dm_list *allocate_pvs);
+
+/* --  metadata/raid_manip.c */
+
 struct cmd_vg *cmd_vg_add(struct dm_pool *mem, struct dm_list *cmd_vgs,
                          const char *vg_name, const char *vgid,
                          uint32_t flags);
@@ -690,15 +822,16 @@ int lv_read_replicator_vgs(struct logical_volume *lv);
 void lv_release_replicator_vgs(struct logical_volume *lv);
 
 struct logical_volume *find_pvmove_lv(struct volume_group *vg,
-                                     struct device *dev, uint32_t lv_type);
+                                     struct device *dev, uint64_t lv_type);
 struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd,
                                                  struct volume_group *vg,
                                                  const char *name,
                                                  const char *uuid,
-                                                 uint32_t lv_type);
+                                                 uint64_t lv_type);
+struct logical_volume *find_pvmove_lv_in_lv(struct logical_volume *lv);
 const char *get_pvmove_pvname_from_lv(struct logical_volume *lv);
 const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr);
-percent_t copy_percent(struct logical_volume *lv_mirr);
+percent_t copy_percent(const struct logical_volume *lv_mirr);
 struct dm_list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
                          struct logical_volume *lv);
 
@@ -720,8 +853,10 @@ int vg_check_write_mode(struct volume_group *vg);
 int lv_has_unknown_segments(const struct logical_volume *lv);
 int vg_has_unknown_segments(const struct volume_group *vg);
 
+int vg_mark_partial_lvs(struct volume_group *vg, int clear);
+
 struct vgcreate_params {
-       char *vg_name;
+       const char *vg_name;
        uint32_t extent_size;
        size_t max_pv;
        size_t max_lv;
index 5f75a66dc3d48daabde009b6931fc0e58b0a9f65..c210a637e413ef7310c6a7c9e76b0251395619dd 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -20,6 +20,7 @@
 #include "lvm-string.h"
 #include "lvm-file.h"
 #include "lvmcache.h"
+#include "lvmetad.h"
 #include "memlock.h"
 #include "str_list.h"
 #include "pv_alloc.h"
@@ -29,7 +30,6 @@
 #include "locking.h"
 #include "archiver.h"
 #include "defaults.h"
-#include "filter-persistent.h"
 
 #include <math.h>
 #include <sys/param.h>
@@ -37,8 +37,7 @@
 static struct physical_volume *_pv_read(struct cmd_context *cmd,
                                        struct dm_pool *pvmem,
                                        const char *pv_name,
-                                       struct dm_list *mdas,
-                                       uint64_t *label_sector,
+                                       struct format_instance *fid,
                                        int warnings, int scan_label_only);
 
 static struct physical_volume *_find_pv_by_name(struct cmd_context *cmd,
@@ -166,21 +165,29 @@ void add_pvl_to_vgs(struct volume_group *vg, struct pv_list *pvl)
        dm_list_add(&vg->pvs, &pvl->list);
        vg->pv_count++;
        pvl->pv->vg = vg;
+       pv_set_fid(pvl->pv, vg->fid);
 }
 
 void del_pvl_from_vgs(struct volume_group *vg, struct pv_list *pvl)
 {
+       struct lvmcache_info *info;
+
        vg->pv_count--;
        dm_list_del(&pvl->list);
-       pvl->pv->vg = NULL; /* orphan */
-}
 
+       pvl->pv->vg = vg->fid->fmt->orphan_vg; /* orphan */
+       if ((info = lvmcache_info_from_pvid((const char *) &pvl->pv->id, 0)))
+               lvmcache_fid_add_mdas(info, vg->fid->fmt->orphan_vg->fid,
+                                     (const char *) &pvl->pv->id, ID_LEN);
+       pv_set_fid(pvl->pv, vg->fid->fmt->orphan_vg->fid);
+}
 
 /**
  * add_pv_to_vg - Add a physical volume to a volume group
  * @vg - volume group to add to
  * @pv_name - name of the pv (to be removed)
  * @pv - physical volume to add to volume group
+ * @pp - physical volume creation params (OPTIONAL)
  *
  * Returns:
  *  0 - failure
@@ -188,13 +195,13 @@ void del_pvl_from_vgs(struct volume_group *vg, struct pv_list *pvl)
  * FIXME: remove pv_name - obtain safely from pv
  */
 int add_pv_to_vg(struct volume_group *vg, const char *pv_name,
-                struct physical_volume *pv)
+                struct physical_volume *pv, struct pvcreate_params *pp)
 {
+       struct pv_to_create *pvc;
        struct pv_list *pvl;
        struct format_instance *fid = vg->fid;
        struct dm_pool *mem = vg->vgmem;
        char uuid[64] __attribute__((aligned(8)));
-       struct dm_list *mdas;
 
        log_verbose("Adding physical volume '%s' to volume group '%s'",
                    pv_name, vg->name);
@@ -238,24 +245,7 @@ int add_pv_to_vg(struct volume_group *vg, const char *pv_name,
         */
        pv->pe_alloc_count = 0;
 
-       /*
-        * FIXME: this does not work entirely correctly in the case where a PV
-        * has 2 mdas and only one is ignored; ideally all non-ignored mdas
-        * should be placed on metadata_areas list and ignored on the
-        * metadata_areas_ignored list; however this requires another
-        * fairly complex refactoring to remove the 'mdas' parameter from both
-        * pv_setup and pv_write.  For now, we only put ignored mdas on the
-        * metadata_areas_ignored list if all mdas in the PV are ignored;
-        * otherwise, we use the non-ignored list.
-        */
-       if (!pv_mda_used_count(pv))
-               mdas = &fid->metadata_areas_ignored;
-       else
-               mdas = &fid->metadata_areas_in_use;
-
-       if (!fid->fmt->ops->pv_setup(fid->fmt, UINT64_C(0), 0,
-                                    vg->extent_size, 0, 0, 0UL, UINT64_C(0),
-                                    0, mdas, pv, vg)) {
+       if (!fid->fmt->ops->pv_setup(fid->fmt, pv, vg)) {
                log_error("Format-specific setup of physical volume '%s' "
                          "failed.", pv_name);
                return 0;
@@ -267,7 +257,7 @@ int add_pv_to_vg(struct volume_group *vg, const char *pv_name,
                        stack;
                        uuid[0] = '\0';
                }
-               log_error("Physical volume '%s (%s)' listed more than once.",
+               log_error("Physical volume '%s (%s)' already in the VG.",
                          pv_name, uuid);
                return 0;
        }
@@ -282,12 +272,12 @@ int add_pv_to_vg(struct volume_group *vg, const char *pv_name,
        if (!alloc_pv_segment_whole_pv(mem, pv))
                return_0;
 
-       if ((uint64_t) vg->extent_count + pv->pe_count > UINT32_MAX) {
+       if ((uint64_t) vg->extent_count + pv->pe_count > MAX_EXTENT_COUNT) {
                log_error("Unable to add %s to %s: new extent count (%"
                          PRIu64 ") exceeds limit (%" PRIu32 ").",
                          pv_name, vg->name,
                          (uint64_t) vg->extent_count + pv->pe_count,
-                         UINT32_MAX);
+                         MAX_EXTENT_COUNT);
                return 0;
        }
 
@@ -296,6 +286,16 @@ int add_pv_to_vg(struct volume_group *vg, const char *pv_name,
        vg->extent_count += pv->pe_count;
        vg->free_count += pv->pe_count;
 
+       if (pv->status & UNLABELLED_PV) {
+               if (!(pvc = dm_pool_zalloc(mem, sizeof(*pvc)))) {
+                       log_error("pv_to_create allocation for '%s' failed", pv_name);
+                       return 0;
+               }
+               pvc->pv = pv;
+               pvc->pp = pp;
+               dm_list_add(&vg->pvs_to_create, &pvc->list);
+       }
+
        return 1;
 }
 
@@ -305,6 +305,10 @@ static int _copy_pv(struct dm_pool *pvmem,
 {
        memcpy(pv_to, pv_from, sizeof(*pv_to));
 
+       /* We must use pv_set_fid here to update the reference counter! */
+       pv_to->fid = NULL;
+       pv_set_fid(pv_to, pv_from->fid);
+
        if (!(pv_to->vg_name = dm_pool_strdup(pvmem, pv_from->vg_name)))
                return_0;
 
@@ -366,7 +370,7 @@ int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
                }
        }
 out:
-       free_vg(vg);
+       release_vg(vg);
        return r;
 }
 
@@ -444,12 +448,12 @@ int move_pvs_used_by_lv(struct volume_group *vg_from,
 
 static int validate_new_vg_name(struct cmd_context *cmd, const char *vg_name)
 {
-       char vg_path[PATH_MAX];
+       static char vg_path[PATH_MAX];
 
        if (!validate_name(vg_name))
                return_0;
 
-       snprintf(vg_path, PATH_MAX, "%s%s", cmd->dev_dir, vg_name);
+       snprintf(vg_path, sizeof(vg_path), "%s%s", cmd->dev_dir, vg_name);
        if (path_exists(vg_path)) {
                log_error("%s: already exists in filesystem", vg_path);
                return 0;
@@ -603,7 +607,7 @@ int vg_remove(struct volume_group *vg)
                }
 
                /* FIXME Write to same sector label was read from */
-               if (!pv_write(vg->cmd, pv, NULL, INT64_C(-1))) {
+               if (!pv_write(vg->cmd, pv, 0)) {
                        log_error("Failed to remove physical volume \"%s\""
                                  " from volume group \"%s\"",
                                  pv_dev_name(pv), vg->name);
@@ -611,10 +615,15 @@ int vg_remove(struct volume_group *vg)
                }
        }
 
-       backup_remove(vg->cmd, vg->name);
+       /* FIXME Handle partial failures from above. */
+       if (!lvmetad_vg_remove(vg))
+               stack;
+
+       if (!backup_remove(vg->cmd, vg->name))
+               stack;
 
        if (ret)
-               log_print("Volume group \"%s\" successfully removed", vg->name);
+               log_print_unless_silent("Volume group \"%s\" successfully removed", vg->name);
        else
                log_error("Volume group \"%s\" not properly removed", vg->name);
 
@@ -636,18 +645,20 @@ static int vg_extend_single_pv(struct volume_group *vg, char *pv_name,
 {
        struct physical_volume *pv;
 
-       pv = pv_by_path(vg->fid->fmt->cmd, pv_name);
+       if (!(pv = pv_by_path(vg->fid->fmt->cmd, pv_name)))
+               stack;
        if (!pv && !pp) {
                log_error("%s not identified as an existing "
                          "physical volume", pv_name);
                return 0;
        } else if (!pv && pp) {
-               pv = pvcreate_single(vg->cmd, pv_name, pp);
-               if (!pv)
-                       return 0;
+               if (!(pv = pvcreate_single(vg->cmd, pv_name, pp, 0)))
+                       return_0;
+       }
+       if (!add_pv_to_vg(vg, pv_name, pv, pp)) {
+               free_pv_fid(pv);
+               return_0;
        }
-       if (!add_pv_to_vg(vg, pv_name, pv))
-               return 0;
        return 1;
 }
 
@@ -661,33 +672,38 @@ static int vg_extend_single_pv(struct volume_group *vg, char *pv_name,
  * - pp: parameters to pass to implicit pvcreate; if NULL, do not pvcreate
  *
  */
-int vg_extend(struct volume_group *vg, int pv_count, char **pv_names,
+int vg_extend(struct volume_group *vg, int pv_count, const char *const *pv_names,
              struct pvcreate_params *pp)
 {
        int i;
+       char *pv_name;
 
        if (_vg_bad_status_bits(vg, RESIZEABLE_VG))
-               return 0;
+               return_0;
 
        /* attach each pv */
        for (i = 0; i < pv_count; i++) {
-               unescape_colons_and_at_signs(pv_names[i], NULL, NULL);
-               if (!vg_extend_single_pv(vg, pv_names[i], pp))
-                       goto bad;
+               if (!(pv_name = dm_strdup(pv_names[i]))) {
+                       log_error("Failed to duplicate pv name %s.", pv_names[i]);
+                       return 0;
+               }
+               dm_unescape_colons_and_at_signs(pv_name, NULL, NULL);
+               if (!vg_extend_single_pv(vg, pv_name, pp)) {
+                       log_error("Unable to add physical volume '%s' to "
+                                 "volume group '%s'.", pv_name, vg->name);
+                       dm_free(pv_name);
+                       return 0;
+               }
+               dm_free(pv_name);
        }
 
 /* FIXME Decide whether to initialise and add new mdahs to format instance */
 
        return 1;
-
-      bad:
-       log_error("Unable to add physical volume '%s' to "
-                 "volume group '%s'.", pv_names[i], vg->name);
-       return 0;
 }
 
 /* FIXME: use this inside vgreduce_single? */
-int vg_reduce(struct volume_group *vg, char *pv_name)
+int vg_reduce(struct volume_group *vg, const char *pv_name)
 {
        struct physical_volume *pv;
        struct pv_list *pvl;
@@ -754,13 +770,9 @@ int lv_change_tag(struct logical_volume *lv, const char *tag, int add_tag)
                                  tag, lv->vg->name, lv->name);
                        return 0;
                }
-       } else {
-               if (!str_list_del(&lv->tags, tag)) {
-                       log_error("Failed to remove tag %s from %s/%s",
-                                 tag, lv->vg->name, lv->name);
-                       return 0;
-               }
-       }
+       } else
+               str_list_del(&lv->tags, tag);
+
        return 1;
 }
 
@@ -784,13 +796,9 @@ int vg_change_tag(struct volume_group *vg, const char *tag, int add_tag)
                                  tag, vg->name);
                        return 0;
                }
-       } else {
-               if (!str_list_del(&vg->tags, tag)) {
-                       log_error("Failed to remove tag %s from volume group "
-                                 "%s", tag, vg->name);
-                       return 0;
-               }
-       }
+       } else
+               str_list_del(&vg->tags, tag);
+
        return 1;
 }
 
@@ -847,25 +855,22 @@ int vgcreate_params_validate(struct cmd_context *cmd,
  * possible failure code or zero for success.
  */
 static struct volume_group *_vg_make_handle(struct cmd_context *cmd,
-                            struct volume_group *vg,
-                            uint32_t failure)
+                                           struct volume_group *vg,
+                                           uint32_t failure)
 {
-       struct dm_pool *vgmem;
-
-       if (!vg) {
-               if (!(vgmem = dm_pool_create("lvm2 vg_handle", VG_MEMPOOL_CHUNK)) ||
-                   !(vg = dm_pool_zalloc(vgmem, sizeof(*vg)))) {
-                       log_error("Error allocating vg handle.");
-                       if (vgmem)
-                               dm_pool_destroy(vgmem);
-                       return_NULL;
-               }
-               vg->vgmem = vgmem;
+       /* Never return a cached VG structure for a failure */
+       if (vg && vg->vginfo && failure != SUCCESS) {
+               release_vg(vg);
+               vg = NULL;
        }
 
-       vg->read_status = failure;
+       if (!vg && !(vg = alloc_vg("vg_make_handle", cmd, NULL)))
+               return_NULL;
 
-       return (struct volume_group *)vg;
+       if (vg->read_status != failure)
+               vg->read_status = failure;
+
+       return vg;
 }
 
 int lv_has_unknown_segments(const struct logical_volume *lv)
@@ -900,8 +905,9 @@ int vg_has_unknown_segments(const struct volume_group *vg)
 struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name)
 {
        struct volume_group *vg;
+       struct format_instance_ctx fic;
+       struct format_instance *fid;
        int consistent = 0;
-       struct dm_pool *mem;
        uint32_t rc;
 
        if (!validate_name(vg_name)) {
@@ -920,14 +926,14 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name)
        /* is this vg name already in use ? */
        if ((vg = vg_read_internal(cmd, vg_name, NULL, 1, &consistent))) {
                log_error("A volume group called '%s' already exists.", vg_name);
-               unlock_and_free_vg(cmd, vg, vg_name);
+               unlock_and_release_vg(cmd, vg, vg_name);
                return _vg_make_handle(cmd, NULL, FAILED_EXIST);
        }
 
-       if (!(mem = dm_pool_create("lvm2 vg_create", VG_MEMPOOL_CHUNK)))
-               goto_bad;
+       /* Strip dev_dir if present */
+       vg_name = strip_dir(vg_name, cmd->dev_dir);
 
-       if (!(vg = dm_pool_zalloc(mem, sizeof(*vg))))
+       if (!(vg = alloc_vg("vg_create", cmd, vg_name)))
                goto_bad;
 
        if (!id_create(&vg->id)) {
@@ -936,19 +942,8 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name)
                goto bad;
        }
 
-       /* Strip dev_dir if present */
-       vg_name = strip_dir(vg_name, cmd->dev_dir);
-
-       vg->vgmem = mem;
-       vg->cmd = cmd;
-
-       if (!(vg->name = dm_pool_strdup(mem, vg_name)))
-               goto_bad;
-
-       vg->seqno = 0;
-
        vg->status = (RESIZEABLE_VG | LVM_READ | LVM_WRITE);
-       if (!(vg->system_id = dm_pool_alloc(mem, NAME_LEN)))
+       if (!(vg->system_id = dm_pool_zalloc(vg->vgmem, NAME_LEN + 1)))
                goto_bad;
 
        *vg->system_id = '\0';
@@ -964,20 +959,15 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name)
        vg->mda_copies = DEFAULT_VGMETADATACOPIES;
 
        vg->pv_count = 0;
-       dm_list_init(&vg->pvs);
-
-       dm_list_init(&vg->lvs);
 
-       dm_list_init(&vg->tags);
-
-       /* initialize removed_pvs list */
-       dm_list_init(&vg->removed_pvs);
-
-       if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg_name,
-                                                      NULL, NULL))) {
+       fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
+       fic.context.vg_ref.vg_name = vg_name;
+       fic.context.vg_ref.vg_id = NULL;
+       if (!(fid = cmd->fmt->ops->create_instance(cmd->fmt, &fic))) {
                log_error("Failed to create format instance");
                goto bad;
        }
+       vg_set_fid(vg, fid);
 
        if (vg->fid->fmt->ops->vg_setup &&
            !vg->fid->fmt->ops->vg_setup(vg->fid, vg)) {
@@ -988,7 +978,7 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name)
        return _vg_make_handle(cmd, vg, SUCCESS);
 
 bad:
-       unlock_and_free_vg(cmd, vg, vg_name);
+       unlock_and_release_vg(cmd, vg, vg_name);
        /* FIXME: use _vg_make_handle() w/proper error code */
        return NULL;
 }
@@ -998,16 +988,16 @@ uint64_t extents_from_size(struct cmd_context *cmd, uint64_t size,
 {
        if (size % extent_size) {
                size += extent_size - size % extent_size;
-               log_print("Rounding up size to full physical extent %s",
-                         display_size(cmd, size));
+               log_print_unless_silent("Rounding up size to full physical extent %s",
+                                       display_size(cmd, size));
        }
 
-       if (size > (uint64_t) UINT32_MAX * extent_size) {
+       if (size > (uint64_t) MAX_EXTENT_COUNT * extent_size) {
                log_error("Volume too large (%s) for extent size %s. "
                          "Upper limit is %s.",
                          display_size(cmd, size),
                          display_size(cmd, (uint64_t) extent_size),
-                         display_size(cmd, (uint64_t) UINT32_MAX *
+                         display_size(cmd, (uint64_t) MAX_EXTENT_COUNT *
                                       extent_size));
                return 0;
        }
@@ -1085,6 +1075,12 @@ static dm_bitset_t _bitset_with_random_bits(struct dm_pool *mem, uint32_t num_bi
                }
        }
 
+       if (!dm_pool_grow_object(mem, "\0", 1)) {
+               log_error("Failed to finish list of random bits.");
+               dm_pool_free(mem, bs);
+               return NULL;
+       }
+
        log_debug("Selected %" PRIu32 " random bits from %" PRIu32 ": %s", num_set_bits, num_bits, (char *) dm_pool_end_object(mem));
 
        return bs;
@@ -1309,7 +1305,7 @@ static int _wipe_sb(struct device *dev, const char *type, const char *name,
                return 0;
        }
 
-       log_print("Wiping %s on %s.", type, name);
+       log_print_unless_silent("Wiping %s on %s.", type, name);
        if (!dev_set(dev, superblock, wipe_len, 0)) {
                log_error("Failed to wipe %s on %s.", type, name);
                return 0;
@@ -1327,14 +1323,12 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name,
 {
        struct physical_volume *pv;
        struct device *dev;
-       struct dm_list mdas;
-
-       dm_list_init(&mdas);
 
        /* FIXME Check partition type is LVM unless --force is given */
 
        /* Is there a pv here already? */
-       pv = pv_read(cmd, name, &mdas, NULL, 0, 0);
+       if (!(pv = pv_read(cmd, name, 0, 0)))
+               stack;
 
        /*
         * If a PV has no MDAs it may appear to be an orphan until the
@@ -1342,10 +1336,12 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name,
         * this means checking every VG by scanning every PV on the
         * system.
         */
-       if (pv && is_orphan(pv) && mdas_empty_or_ignored(&mdas)) {
+       if (pv && is_orphan(pv) && !dm_list_size(&pv->fid->metadata_areas_in_use)) {
+               free_pv_fid(pv);
                if (!scan_vgs_for_pvs(cmd, 0))
                        return_0;
-               pv = pv_read(cmd, name, NULL, NULL, 0, 0);
+               if (!(pv = pv_read(cmd, name, 0, 0)))
+                       stack;
        }
 
        /* Allow partial & exported VGs to be destroyed. */
@@ -1353,25 +1349,27 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name,
        if (pv && !is_orphan(pv) && pp->force != DONT_PROMPT_OVERRIDE) {
                log_error("Can't initialize physical volume \"%s\" of "
                          "volume group \"%s\" without -ff", name, pv_vg_name(pv));
-               return 0;
+               goto bad;
        }
 
        /* prompt */
        if (pv && !is_orphan(pv) && !pp->yes &&
            yes_no_prompt(_really_init, name, pv_vg_name(pv)) == 'n') {
                log_error("%s: physical volume not initialized", name);
-               return 0;
+               goto bad;
        }
 
        if (sigint_caught())
-               return 0;
+               goto_bad;
 
        dev = dev_cache_get(name, cmd->filter);
 
        /* Is there an md superblock here? */
        /* FIXME: still possible issues here - rescan cache? */
        if (!dev && md_filtering()) {
-               refresh_filters(cmd);
+               if (!refresh_filters(cmd))
+                       goto_bad;
+
                init_md_filtering(0);
                dev = dev_cache_get(name, cmd->filter);
                init_md_filtering(1);
@@ -1379,7 +1377,7 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name,
 
        if (!dev) {
                log_error("Device %s not found (or ignored by filtering).", name);
-               return 0;
+               goto bad;
        }
 
        /*
@@ -1389,20 +1387,20 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name,
                /* FIXME Detect whether device-mapper itself is still using it */
                log_error("Can't open %s exclusively.  Mounted filesystem?",
                          name);
-               return 0;
+               goto bad;
        }
 
        if (!_wipe_sb(dev, "software RAID md superblock", name, 4, pp, dev_is_md))
-               return 0;
+               goto_bad;
 
        if (!_wipe_sb(dev, "swap signature", name, 10, pp, dev_is_swap))
-               return 0;
+               goto_bad;
 
        if (!_wipe_sb(dev, "LUKS signature", name, 8, pp, dev_is_luks))
-               return 0;
+               goto_bad;
 
        if (sigint_caught())
-               return 0;
+               goto_bad;
 
        if (pv && !is_orphan(pv) && pp->force) {
                log_warn("WARNING: Forcing physical volume creation on "
@@ -1412,7 +1410,12 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name,
                          !is_orphan(pv) ? "\"" : "");
        }
 
+       free_pv_fid(pv);
        return 1;
+
+bad:
+       free_pv_fid(pv);
+       return 0;
 }
 
 void pvcreate_params_set_defaults(struct pvcreate_params *pp)
@@ -1435,6 +1438,49 @@ void pvcreate_params_set_defaults(struct pvcreate_params *pp)
        pp->metadataignore = DEFAULT_PVMETADATAIGNORE;
 }
 
+
+static int _pvcreate_write(struct cmd_context *cmd, struct pv_to_create *pvc)
+{
+       int zero = pvc->pp->zero;
+       struct physical_volume *pv = pvc->pv;
+       struct device *dev = pv->dev;
+       const char *pv_name = dev_name(dev);
+
+       /* Wipe existing label first */
+       if (!label_remove(pv_dev(pv))) {
+               log_error("Failed to wipe existing label on %s", pv_name);
+               return 0;
+       }
+
+       if (zero) {
+               log_verbose("Zeroing start of device %s", pv_name);
+               if (!dev_open_quiet(dev)) {
+                       log_error("%s not opened: device not zeroed", pv_name);
+                       return 0;
+               }
+
+               if (!dev_set(dev, UINT64_C(0), (size_t) 2048, 0)) {
+                       log_error("%s not wiped: aborting", pv_name);
+                       if (!dev_close(dev))
+                               stack;
+                       return 0;
+               }
+               if (!dev_close(dev))
+                       stack;
+       }
+
+       log_verbose("Writing physical volume data to disk \"%s\"",
+                   pv_name);
+
+       if (!(pv_write(cmd, pv, 1))) {
+               log_error("Failed to write physical volume \"%s\"", pv_name);
+               return 0;
+       }
+
+       log_print_unless_silent("Physical volume \"%s\" successfully created", pv_name);
+       return 1;
+}
+
 /*
  * pvcreate_single() - initialize a device with PV label and metadata area
  *
@@ -1448,9 +1494,10 @@ void pvcreate_params_set_defaults(struct pvcreate_params *pp)
  */
 struct physical_volume * pvcreate_single(struct cmd_context *cmd,
                                         const char *pv_name,
-                                        struct pvcreate_params *pp)
+                                        struct pvcreate_params *pp,
+                                        int write_now)
 {
-       struct physical_volume *pv;
+       struct physical_volume *pv = NULL;
        struct device *dev;
        struct dm_list mdas;
        struct pvcreate_params default_pp;
@@ -1461,100 +1508,70 @@ struct physical_volume * pvcreate_single(struct cmd_context *cmd,
                pp = &default_pp;
 
        if (pp->idp) {
-               if ((dev = device_from_pvid(cmd, pp->idp, NULL)) &&
+               if ((dev = lvmcache_device_from_pvid(cmd, pp->idp, NULL, NULL)) &&
                    (dev != dev_cache_get(pv_name, cmd->filter))) {
                        if (!id_write_format((const struct id*)&pp->idp->uuid,
                            buffer, sizeof(buffer)))
-                               return_NULL;
+                               goto_bad;
                        log_error("uuid %s already in use on \"%s\"", buffer,
                                  dev_name(dev));
-                       return NULL;
+                       goto bad;
                }
        }
 
        if (!pvcreate_check(cmd, pv_name, pp))
-               goto error;
+               goto_bad;
 
        if (sigint_caught())
-               goto error;
+               goto_bad;
 
        if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
                log_error("%s: Couldn't find device.  Check your filters?",
                          pv_name);
-               goto error;
+               goto bad;
        }
 
        dm_list_init(&mdas);
+
        if (!(pv = pv_create(cmd, dev, pp->idp, pp->size,
                             pp->data_alignment, pp->data_alignment_offset,
-                            pp->pe_start, pp->extent_count, pp->extent_size,
-                            pp->pvmetadatacopies, pp->pvmetadatasize,
-                            pp->metadataignore, &mdas))) {
+                            pp->pe_start ? pp->pe_start : PV_PE_START_CALC,
+                            pp->extent_count, pp->extent_size,
+                            pp->labelsector, pp->pvmetadatacopies,
+                            pp->pvmetadatasize, pp->metadataignore))) {
                log_error("Failed to setup physical volume \"%s\"", pv_name);
-               goto error;
+               goto bad;
        }
 
        log_verbose("Set up physical volume for \"%s\" with %" PRIu64
                    " available sectors", pv_name, pv_size(pv));
 
-       /* Wipe existing label first */
-       if (!label_remove(pv_dev(pv))) {
-               log_error("Failed to wipe existing label on %s", pv_name);
-               goto error;
-       }
-
-       if (pp->zero) {
-               log_verbose("Zeroing start of device %s", pv_name);
-               if (!dev_open_quiet(dev)) {
-                       log_error("%s not opened: device not zeroed", pv_name);
-                       goto error;
-               }
-
-               if (!dev_set(dev, UINT64_C(0), (size_t) 2048, 0)) {
-                       log_error("%s not wiped: aborting", pv_name);
-                       dev_close(dev);
-                       goto error;
-               }
-               dev_close(dev);
-       }
-
-       log_very_verbose("Writing physical volume data to disk \"%s\"",
-                        pv_name);
-
-       if (!(pv_write(cmd, pv, &mdas, pp->labelsector))) {
-               log_error("Failed to write physical volume \"%s\"", pv_name);
-               goto error;
+       if (write_now) {
+               struct pv_to_create pvc;
+               pvc.pp = pp;
+               pvc.pv = pv;
+               if (!_pvcreate_write(cmd, &pvc))
+                       goto bad;
+       } else {
+               pv->status |= UNLABELLED_PV;
        }
 
-       log_print("Physical volume \"%s\" successfully created", pv_name);
-
        return pv;
 
-      error:
+bad:
        return NULL;
 }
 
-static void _free_pv(struct dm_pool *mem, struct physical_volume *pv)
-{
-       dm_pool_free(mem, pv);
-}
-
 static struct physical_volume *_alloc_pv(struct dm_pool *mem, struct device *dev)
 {
-       struct physical_volume *pv = dm_pool_zalloc(mem, sizeof(*pv));
+       struct physical_volume *pv;
 
-       if (!pv)
-               return_NULL;
+       if (!(pv = dm_pool_zalloc(mem, sizeof(*pv)))) {
+               log_error("Failed to allocate pv structure.");
+               return NULL;
+       }
 
-       pv->pe_size = 0;
-       pv->pe_start = 0;
-       pv->pe_count = 0;
-       pv->pe_alloc_count = 0;
-       pv->pe_align = 0;
-       pv->pe_align_offset = 0;
-       pv->fmt = NULL;
        pv->dev = dev;
-
        pv->status = ALLOCATABLE_PV;
 
        dm_list_init(&pv->tags);
@@ -1565,6 +1582,7 @@ static struct physical_volume *_alloc_pv(struct dm_pool *mem, struct device *dev
 
 /**
  * pv_create - initialize a physical volume for use with a volume group
+ * created PV belongs to Orphan VG.
  *
  * @fmt: format type
  * @dev: PV device to initialize
@@ -1593,15 +1611,19 @@ struct physical_volume *pv_create(const struct cmd_context *cmd,
                                  uint64_t pe_start,
                                  uint32_t existing_extent_count,
                                  uint32_t existing_extent_size,
-                                 int pvmetadatacopies, uint64_t pvmetadatasize,
-                                 unsigned metadataignore, struct dm_list *mdas)
+                                 uint64_t label_sector,
+                                 unsigned pvmetadatacopies,
+                                 uint64_t pvmetadatasize,
+                                 unsigned metadataignore)
 {
        const struct format_type *fmt = cmd->fmt;
-       struct dm_pool *mem = fmt->cmd->mem;
+       struct dm_pool *mem = fmt->orphan_vg->vgmem;
        struct physical_volume *pv = _alloc_pv(mem, dev);
+       unsigned mda_index;
+       struct pv_list *pvl;
 
        if (!pv)
-               return NULL;
+               return_NULL;
 
        if (id)
                memcpy(&pv->id, id, sizeof(*id));
@@ -1625,9 +1647,9 @@ struct physical_volume *pv_create(const struct cmd_context *cmd,
                pv->size = size;
        }
 
-       if (pv->size < PV_MIN_SIZE) {
-               log_error("%s: Size must exceed minimum of %ld sectors.",
-                         pv_dev_name(pv), PV_MIN_SIZE);
+       if (pv->size < pv_min_size()) {
+               log_error("%s: Size must exceed minimum of %" PRIu64 " sectors.",
+                         pv_dev_name(pv), pv_min_size());
                goto bad;
        }
 
@@ -1637,23 +1659,45 @@ struct physical_volume *pv_create(const struct cmd_context *cmd,
                goto bad;
        }
 
+       if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl)))) {
+               log_error("pv_list allocation in pv_create failed");
+               goto bad;
+       }
+
+       pvl->pv = pv;
+       add_pvl_to_vgs(fmt->orphan_vg, pvl);
+       fmt->orphan_vg->extent_count += pv->pe_count;
+       fmt->orphan_vg->free_count += pv->pe_count;
+
        pv->fmt = fmt;
        pv->vg_name = fmt->orphan_vg_name;
 
-       if (!fmt->ops->pv_setup(fmt, pe_start, existing_extent_count,
-                               existing_extent_size, data_alignment,
-                               data_alignment_offset,
-                               pvmetadatacopies, pvmetadatasize,
-                               metadataignore, mdas, pv, NULL)) {
-               log_error("%s: Format-specific setup of physical volume "
-                         "failed.", pv_dev_name(pv));
+       if (!fmt->ops->pv_initialise(fmt, label_sector, pe_start,
+                                    existing_extent_count, existing_extent_size,
+                                    data_alignment, data_alignment_offset, pv)) {
+               log_error("Format-specific initialisation of physical "
+                         "volume %s failed.", pv_dev_name(pv));
                goto bad;
        }
 
+       for (mda_index = 0; mda_index < pvmetadatacopies; mda_index++) {
+               if (pv->fmt->ops->pv_add_metadata_area &&
+                   !pv->fmt->ops->pv_add_metadata_area(pv->fmt, pv,
+                                       pe_start != PV_PE_START_CALC,
+                                       mda_index, pvmetadatasize,
+                                       metadataignore)) {
+                       log_error("Failed to add metadata area for "
+                                 "new physical volume %s", pv_dev_name(pv));
+                       goto bad;
+               }
+       }
+
        return pv;
 
       bad:
-       _free_pv(mem, pv);
+       // FIXME: detach from orphan in error path
+       //free_pv_fid(pv);
+       //dm_pool_free(mem, pv);
        return NULL;
 }
 
@@ -1801,31 +1845,34 @@ struct physical_volume *find_pv_by_name(struct cmd_context *cmd,
 static struct physical_volume *_find_pv_by_name(struct cmd_context *cmd,
                                                const char *pv_name)
 {
-       struct dm_list mdas;
        struct physical_volume *pv;
 
-       dm_list_init(&mdas);
-       if (!(pv = _pv_read(cmd, cmd->mem, pv_name, &mdas, NULL, 1, 0))) {
+       if (!(pv = _pv_read(cmd, cmd->mem, pv_name, NULL, 1, 0))) {
                log_error("Physical volume %s not found", pv_name);
-               return NULL;
+               goto bad;
        }
 
-       if (is_orphan_vg(pv->vg_name) && mdas_empty_or_ignored(&mdas)) {
+       if (is_orphan_vg(pv->vg_name) && !dm_list_size(&pv->fid->metadata_areas_in_use)) {
                /* If a PV has no MDAs - need to search all VGs for it */
                if (!scan_vgs_for_pvs(cmd, 1))
-                       return_NULL;
-               if (!(pv = _pv_read(cmd, cmd->mem, pv_name, NULL, NULL, 1, 0))) {
+                       goto_bad;
+               free_pv_fid(pv);
+               if (!(pv = _pv_read(cmd, cmd->mem, pv_name, NULL, 1, 0))) {
                        log_error("Physical volume %s not found", pv_name);
-                       return NULL;
+                       goto bad;
                }
        }
 
        if (is_orphan_vg(pv->vg_name)) {
                log_error("Physical volume %s not in a volume group", pv_name);
-               return NULL;
+               goto bad;
        }
 
        return pv;
+
+bad:
+       free_pv_fid(pv);
+       return NULL;
 }
 
 /* Find segment at a given logical extent in an LV */
@@ -1850,6 +1897,16 @@ struct lv_segment *first_seg(const struct logical_volume *lv)
        return NULL;
 }
 
+struct lv_segment *last_seg(const struct logical_volume *lv)
+{
+       struct lv_segment *seg;
+
+       dm_list_iterate_back_items(seg, &lv->segments)
+               return seg;
+
+       return NULL;
+}
+
 int vg_remove_mdas(struct volume_group *vg)
 {
        struct metadata_area *mda;
@@ -1874,7 +1931,7 @@ int vgs_are_compatible(struct cmd_context *cmd __attribute__((unused)),
 {
        struct lv_list *lvl1, *lvl2;
        struct pv_list *pvl;
-       char *name1, *name2;
+       const char *name1, *name2;
 
        if (lvs_in_vg_activated(vg_from)) {
                log_error("Logical volumes in \"%s\" must be inactive",
@@ -1968,23 +2025,11 @@ static int _lv_postorder_visit(struct logical_volume *,
                               int (*fn)(struct logical_volume *lv, void *data),
                               void *data);
 
-static int _lv_postorder_level(struct logical_volume *lv, void *data)
-{
-       struct _lv_postorder_baton *baton = data;
-       if (lv->status & POSTORDER_OPEN_FLAG)
-               return 1; // a data structure loop has closed...
-       lv->status |= POSTORDER_OPEN_FLAG;
-       int r =_lv_postorder_visit(lv, baton->fn, baton->data);
-       lv->status &= ~POSTORDER_OPEN_FLAG;
-       lv->status |= POSTORDER_FLAG;
-       return r;
-};
-
 static int _lv_each_dependency(struct logical_volume *lv,
                               int (*fn)(struct logical_volume *lv, void *data),
                               void *data)
 {
-       int i, s;
+       unsigned i, s;
        struct lv_segment *lvseg;
 
        struct logical_volume *deps[] = {
@@ -2002,6 +2047,10 @@ static int _lv_each_dependency(struct logical_volume *lv,
                        return_0;
                if (lvseg->rlog_lv && !fn(lvseg->rlog_lv, data))
                        return_0;
+               if (lvseg->pool_lv && !fn(lvseg->pool_lv, data))
+                       return_0;
+               if (lvseg->metadata_lv && !fn(lvseg->metadata_lv, data))
+                       return_0;
                for (s = 0; s < lvseg->area_count; ++s) {
                        if (seg_type(lvseg, s) == AREA_LV && !fn(seg_lv(lvseg,s), data))
                                return_0;
@@ -2021,6 +2070,12 @@ static int _lv_postorder_cleanup(struct logical_volume *lv, void *data)
        return 1;
 }
 
+static int _lv_postorder_level(struct logical_volume *lv, void *data)
+{
+       struct _lv_postorder_baton *baton = data;
+       return _lv_postorder_visit(lv, baton->fn, baton->data);
+};
+
 static int _lv_postorder_visit(struct logical_volume *lv,
                               int (*fn)(struct logical_volume *lv, void *data),
                               void *data)
@@ -2030,13 +2085,20 @@ static int _lv_postorder_visit(struct logical_volume *lv,
 
        if (lv->status & POSTORDER_FLAG)
                return 1;
+       if (lv->status & POSTORDER_OPEN_FLAG)
+               return 1; // a data structure loop has closed...
+       lv->status |= POSTORDER_OPEN_FLAG;
 
        baton.fn = fn;
        baton.data = data;
        r = _lv_each_dependency(lv, _lv_postorder_level, &baton);
+
        if (r)
                r = fn(lv, data);
 
+       lv->status &= ~POSTORDER_OPEN_FLAG;
+       lv->status |= POSTORDER_FLAG;
+
        return r;
 }
 
@@ -2052,8 +2114,47 @@ static int _lv_postorder(struct logical_volume *lv,
                               void *data)
 {
        int r;
+       int pool_locked = dm_pool_locked(lv->vg->vgmem);
+
+       if (pool_locked && !dm_pool_unlock(lv->vg->vgmem, 0))
+               return_0;
+
        r = _lv_postorder_visit(lv, fn, data);
        _lv_postorder_cleanup(lv, 0);
+
+       if (pool_locked && !dm_pool_lock(lv->vg->vgmem, 0))
+               return_0;
+
+       return r;
+}
+
+/*
+ * Calls _lv_postorder() on each LV from VG. Avoids duplicate transitivity visits.
+ * Clears with _lv_postorder_cleanup() when all LVs were visited by postorder.
+ */
+static int _lv_postorder_vg(struct volume_group *vg,
+                           int (*fn)(struct logical_volume *lv, void *data),
+                           void *data)
+{
+       struct lv_list *lvl;
+       int r = 1;
+       int pool_locked = dm_pool_locked(vg->vgmem);
+
+       if (pool_locked && !dm_pool_unlock(vg->vgmem, 0))
+               return_0;
+
+       dm_list_iterate_items(lvl, &vg->lvs)
+               if (!_lv_postorder_visit(lvl->lv, fn, data)) {
+                       stack;
+                       r = 0;
+               }
+
+       dm_list_iterate_items(lvl, &vg->lvs)
+               _lv_postorder_cleanup(lvl->lv, 0);
+
+       if (pool_locked && !dm_pool_lock(vg->vgmem, 0))
+               return_0;
+
        return r;
 }
 
@@ -2072,7 +2173,7 @@ static int _lv_mark_if_partial_collect(struct logical_volume *lv, void *data)
 
 static int _lv_mark_if_partial_single(struct logical_volume *lv, void *data)
 {
-       int s;
+       unsigned s;
        struct _lv_mark_if_partial_baton baton;
        struct lv_segment *lvseg;
 
@@ -2086,7 +2187,8 @@ static int _lv_mark_if_partial_single(struct logical_volume *lv, void *data)
        }
 
        baton.partial = 0;
-       _lv_each_dependency(lv, _lv_mark_if_partial_collect, &baton);
+       if (!_lv_each_dependency(lv, _lv_mark_if_partial_collect, &baton))
+               return_0;
 
        if (baton.partial)
                lv->status |= PARTIAL_LV;
@@ -2094,26 +2196,21 @@ static int _lv_mark_if_partial_single(struct logical_volume *lv, void *data)
        return 1;
 }
 
-static int _lv_mark_if_partial(struct logical_volume *lv)
-{
-       return _lv_postorder(lv, _lv_mark_if_partial_single, NULL);
-}
-
 /*
  * Mark LVs with missing PVs using PARTIAL_LV status flag. The flag is
  * propagated transitively, so LVs referencing other LVs are marked
  * partial as well, if any of their referenced LVs are marked partial.
  */
-int vg_mark_partial_lvs(struct volume_group *vg)
+int vg_mark_partial_lvs(struct volume_group *vg, int clear)
 {
-       struct logical_volume *lv;
        struct lv_list *lvl;
 
-       dm_list_iterate_items(lvl, &vg->lvs) {
-               lv = lvl->lv;
-               if (!_lv_mark_if_partial(lv))
-                       return_0;
-       }
+       if (clear)
+               dm_list_iterate_items(lvl, &vg->lvs)
+                       lvl->lv->status &= ~PARTIAL_LV;
+
+       if (!_lv_postorder_vg(vg, _lv_mark_if_partial_single, NULL))
+               return_0;
        return 1;
 }
 
@@ -2126,6 +2223,11 @@ static int _lv_read_ahead_single(struct logical_volume *lv, void *data)
        struct lv_segment *seg = first_seg(lv);
        uint32_t seg_read_ahead = 0, *read_ahead = data;
 
+       if (!read_ahead) {
+               log_error(INTERNAL_ERROR "Read ahead data missing.");
+               return 0;
+       }
+
        if (seg && seg->area_count && seg_type(seg, 0) == AREA_PV)
                dev_get_read_ahead(seg_pv(seg, 0)->dev, &seg_read_ahead);
 
@@ -2153,6 +2255,12 @@ void lv_calculate_readahead(const struct logical_volume *lv, uint32_t *read_ahea
        }
 }
 
+struct validate_hash {
+       struct dm_hash_table *lvname;
+       struct dm_hash_table *lvid;
+       struct dm_hash_table *pvid;
+};
+
 /*
  * Check that an LV and all its PV references are correctly listed in vg->lvs
  * and vg->pvs, respectively. This only looks at a single LV, but *not* at the
@@ -2162,21 +2270,14 @@ void lv_calculate_readahead(const struct logical_volume *lv, uint32_t *read_ahea
 static int _lv_validate_references_single(struct logical_volume *lv, void *data)
 {
        struct volume_group *vg = lv->vg;
+       struct validate_hash *vhash = data;
        struct lv_segment *lvseg;
-       struct pv_list *pvl;
-       struct lv_list *lvl;
-       int s;
+       struct physical_volume *pv;
+       unsigned s;
        int r = 1;
-       int ok = 0;
 
-       dm_list_iterate_items(lvl, &vg->lvs) {
-               if (lvl->lv == lv) {
-                       ok = 1;
-                       break;
-               }
-       }
-
-       if (!ok) {
+       if (lv != dm_hash_lookup_binary(vhash->lvid, &lv->lvid.id[1],
+                                       sizeof(lv->lvid.id[1]))) {
                log_error(INTERNAL_ERROR
                          "Referenced LV %s not listed in VG %s.",
                          lv->name, vg->name);
@@ -2185,22 +2286,16 @@ static int _lv_validate_references_single(struct logical_volume *lv, void *data)
 
        dm_list_iterate_items(lvseg, &lv->segments) {
                for (s = 0; s < lvseg->area_count; ++s) {
-                       if (seg_type(lvseg, s) == AREA_PV) {
-                               ok = 0;
-                               /* look up the reference in vg->pvs */
-                               dm_list_iterate_items(pvl, &vg->pvs) {
-                                       if (pvl->pv == seg_pv(lvseg, s)) {
-                                               ok = 1;
-                                               break;
-                                       }
-                               }
-
-                               if (!ok) {
-                                       log_error(INTERNAL_ERROR
-                                                 "Referenced PV %s not listed in VG %s.",
-                                                 pv_dev_name(seg_pv(lvseg, s)), vg->name);
-                                       r = 0;
-                               }
+                       if (seg_type(lvseg, s) != AREA_PV)
+                               continue;
+                       pv = seg_pv(lvseg, s);
+                       /* look up the reference in vg->pvs */
+                       if (pv != dm_hash_lookup_binary(vhash->pvid, &pv->id,
+                                                       sizeof(pv->id))) {
+                               log_error(INTERNAL_ERROR
+                                         "Referenced PV %s not listed in VG %s.",
+                                         pv_dev_name(pv), vg->name);
+                               r = 0;
                        }
                }
        }
@@ -2210,15 +2305,16 @@ static int _lv_validate_references_single(struct logical_volume *lv, void *data)
 
 int vg_validate(struct volume_group *vg)
 {
-       struct pv_list *pvl, *pvl2;
-       struct lv_list *lvl, *lvl2;
+       struct pv_list *pvl;
+       struct lv_list *lvl;
        struct lv_segment *seg;
+       struct str_list *sl;
        char uuid[64] __attribute__((aligned(8)));
        int r = 1;
        uint32_t hidden_lv_count = 0, lv_count = 0, lv_visible_count = 0;
        uint32_t pv_count = 0;
        uint32_t num_snapshots = 0;
-       uint32_t loop_counter1, loop_counter2;
+       struct validate_hash vhash = { NULL };
 
        if (vg->alloc == ALLOC_CLING_BY_TAGS) {
                log_error(INTERNAL_ERROR "VG %s allocation policy set to invalid cling_by_tags.",
@@ -2227,50 +2323,66 @@ int vg_validate(struct volume_group *vg)
        }
 
        /* FIXME Also check there's no data/metadata overlap */
+       if (!(vhash.pvid = dm_hash_create(vg->pv_count))) {
+               log_error("Failed to allocate pvid hash.");
+               return 0;
+       }
+
+       dm_list_iterate_items(sl, &vg->tags)
+               if (!validate_tag(sl->str)) {
+                       log_error(INTERNAL_ERROR "VG %s tag %s has invalid form.",
+                                 vg->name, sl->str);
+                       r = 0;
+               }
+
        dm_list_iterate_items(pvl, &vg->pvs) {
                if (++pv_count > vg->pv_count) {
                        log_error(INTERNAL_ERROR "PV list corruption detected in VG %s.", vg->name);
                        /* FIXME Dump list structure? */
                        r = 0;
                }
+
                if (pvl->pv->vg != vg) {
                        log_error(INTERNAL_ERROR "VG %s PV list entry points "
-                                 "to different VG %s", vg->name,
+                                 "to different VG %s.", vg->name,
                                  pvl->pv->vg ? pvl->pv->vg->name : "NULL");
                        r = 0;
                }
-       }
-
-       loop_counter1 = loop_counter2 = 0;
-       /* FIXME Use temp hash table instead? */
-       dm_list_iterate_items(pvl, &vg->pvs) {
-               if (++loop_counter1 > pv_count)
-                       break;
-               dm_list_iterate_items(pvl2, &vg->pvs) {
-                       if (++loop_counter2 > pv_count)
-                               break;
-                       if (pvl == pvl2)
-                               break;
-                       if (id_equal(&pvl->pv->id,
-                                    &pvl2->pv->id)) {
-                               if (!id_write_format(&pvl->pv->id, uuid,
-                                                    sizeof(uuid)))
-                                        stack;
-                               log_error(INTERNAL_ERROR "Duplicate PV id "
-                                         "%s detected for %s in %s.",
-                                         uuid, pv_dev_name(pvl->pv),
-                                         vg->name);
-                               r = 0;
-                       }
-               }
 
                if (strcmp(pvl->pv->vg_name, vg->name)) {
                        log_error(INTERNAL_ERROR "VG name for PV %s is corrupted.",
                                  pv_dev_name(pvl->pv));
                        r = 0;
                }
+
+               if (dm_hash_lookup_binary(vhash.pvid, &pvl->pv->id,
+                                         sizeof(pvl->pv->id))) {
+                       if (!id_write_format(&pvl->pv->id, uuid,
+                                            sizeof(uuid)))
+                               stack;
+                       log_error(INTERNAL_ERROR "Duplicate PV id "
+                                 "%s detected for %s in %s.",
+                                 uuid, pv_dev_name(pvl->pv),
+                                 vg->name);
+                       r = 0;
+               }
+
+               dm_list_iterate_items(sl, &pvl->pv->tags)
+                       if (!validate_tag(sl->str)) {
+                               log_error(INTERNAL_ERROR "PV %s tag %s has invalid form.",
+                                         pv_dev_name(pvl->pv), sl->str);
+                               r = 0;
+                       }
+
+               if (!dm_hash_insert_binary(vhash.pvid, &pvl->pv->id,
+                                          sizeof(pvl->pv->id), pvl->pv)) {
+                       log_error("Failed to hash pvid.");
+                       r = 0;
+                       break;
+               }
        }
 
+
        if (!check_pv_segments(vg)) {
                log_error(INTERNAL_ERROR "PV segments corrupted in %s.",
                          vg->name);
@@ -2301,6 +2413,18 @@ int vg_validate(struct volume_group *vg)
                        r = 0;
                }
 
+               if (!validate_name(lvl->lv->name)) {
+                       log_error(INTERNAL_ERROR "LV name %s has invalid form.", lvl->lv->name);
+                       r = 0;
+               }
+
+               dm_list_iterate_items(sl, &lvl->lv->tags)
+                       if (!validate_tag(sl->str)) {
+                               log_error(INTERNAL_ERROR "LV %s tag %s has invalid form.",
+                                         lvl->lv->name, sl->str);
+                               r = 0;
+                       }
+
                if (lvl->lv->status & VISIBLE_LV)
                        continue;
 
@@ -2336,35 +2460,37 @@ int vg_validate(struct volume_group *vg)
 
        /* Avoid endless loop if lv->segments list is corrupt */
        if (!r)
-               return r;
+               goto out;
+
+       if (!(vhash.lvname = dm_hash_create(lv_count))) {
+               log_error("Failed to allocate lv_name hash");
+               r = 0;
+               goto out;
+       }
+
+       if (!(vhash.lvid = dm_hash_create(lv_count))) {
+               log_error("Failed to allocate uuid hash");
+               r = 0;
+               goto out;
+       }
 
-       loop_counter1 = loop_counter2 = 0;
-       /* FIXME Use temp hash table instead? */
        dm_list_iterate_items(lvl, &vg->lvs) {
-               if (++loop_counter1 > lv_count)
-                       break;
-               dm_list_iterate_items(lvl2, &vg->lvs) {
-                       if (++loop_counter2 > lv_count)
-                               break;
-                       if (lvl == lvl2)
-                               break;
-                       if (!strcmp(lvl->lv->name, lvl2->lv->name)) {
-                               log_error(INTERNAL_ERROR "Duplicate LV name "
-                                         "%s detected in %s.", lvl->lv->name,
-                                         vg->name);
-                               r = 0;
-                       }
-                       if (id_equal(&lvl->lv->lvid.id[1],
-                                    &lvl2->lv->lvid.id[1])) {
-                               if (!id_write_format(&lvl->lv->lvid.id[1], uuid,
-                                                    sizeof(uuid)))
-                                        stack;
-                               log_error(INTERNAL_ERROR "Duplicate LV id "
-                                         "%s detected for %s and %s in %s.",
-                                         uuid, lvl->lv->name, lvl2->lv->name,
-                                         vg->name);
-                               r = 0;
-                       }
+               if (dm_hash_lookup(vhash.lvname, lvl->lv->name)) {
+                       log_error(INTERNAL_ERROR
+                                 "Duplicate LV name %s detected in %s.",
+                                 lvl->lv->name, vg->name);
+                       r = 0;
+               }
+
+               if (dm_hash_lookup_binary(vhash.lvid, &lvl->lv->lvid.id[1],
+                                         sizeof(lvl->lv->lvid.id[1]))) {
+                       if (!id_write_format(&lvl->lv->lvid.id[1], uuid,
+                                            sizeof(uuid)))
+                               stack;
+                       log_error(INTERNAL_ERROR "Duplicate LV id "
+                                 "%s detected for %s in %s.",
+                                 uuid, lvl->lv->name, vg->name);
+                       r = 0;
                }
 
                if (!check_lv_segments(lvl->lv, 1)) {
@@ -2372,11 +2498,24 @@ int vg_validate(struct volume_group *vg)
                                  lvl->lv->name);
                        r = 0;
                }
-       }
 
-       dm_list_iterate_items(lvl, &vg->lvs) {
-               if (!_lv_postorder(lvl->lv, _lv_validate_references_single, NULL))
+               if (!dm_hash_insert(vhash.lvname, lvl->lv->name, lvl)) {
+                       log_error("Failed to hash lvname.");
                        r = 0;
+                       break;
+               }
+
+               if (!dm_hash_insert_binary(vhash.lvid, &lvl->lv->lvid.id[1],
+                                          sizeof(lvl->lv->lvid.id[1]), lvl->lv)) {
+                       log_error("Failed to hash lvid.");
+                       r = 0;
+                       break;
+               }
+       }
+
+       if (!_lv_postorder_vg(vg, _lv_validate_references_single, &vhash)) {
+               stack;
+               r = 0;
        }
 
        dm_list_iterate_items(lvl, &vg->lvs) {
@@ -2386,14 +2525,14 @@ int vg_validate(struct volume_group *vg)
                        if (seg_is_mirrored(seg)) {
                                if (seg->area_count != 2) {
                                        log_error(INTERNAL_ERROR
-                                                 "Segment %d in %s is not 2-way.",
-                                                 loop_counter1, lvl->lv->name);
+                                                 "Segment in %s is not 2-way.",
+                                                 lvl->lv->name);
                                        r = 0;
                                }
                        } else if (seg->area_count != 1) {
                                log_error(INTERNAL_ERROR
-                                         "Segment %d in %s has wrong number of areas: %d.",
-                                         loop_counter1, lvl->lv->name, seg->area_count);
+                                         "Segment in %s has wrong number of areas: %d.",
+                                         lvl->lv->name, seg->area_count);
                                r = 0;
                        }
                }
@@ -2408,6 +2547,13 @@ int vg_validate(struct volume_group *vg)
 
        if (vg_max_lv_reached(vg))
                stack;
+out:
+       if (vhash.lvid)
+               dm_hash_destroy(vhash.lvid);
+       if (vhash.lvname)
+               dm_hash_destroy(vhash.lvname);
+       if (vhash.pvid)
+               dm_hash_destroy(vhash.pvid);
 
        return r;
 }
@@ -2419,6 +2565,7 @@ int vg_validate(struct volume_group *vg)
 int vg_write(struct volume_group *vg)
 {
        struct dm_list *mdah;
+        struct pv_to_create *pv_to_create;
        struct metadata_area *mda;
 
        if (!vg_validate(vg))
@@ -2454,8 +2601,20 @@ int vg_write(struct volume_group *vg)
                return 0;
        }
 
+       if (critical_section())
+               log_error(INTERNAL_ERROR
+                         "Writing metadata in critical section.");
+
+       /* Unlock memory if possible */
+       memlock_unlock(vg->cmd);
        vg->seqno++;
 
+        dm_list_iterate_items(pv_to_create, &vg->pvs_to_create) {
+               if (!_pvcreate_write(vg->cmd, pv_to_create))
+                       return 0;
+               pv_to_create->pv->status &= ~UNLABELLED_PV;
+        }
+
        /* Write to each copy of the metadata area */
        dm_list_iterate_items(mda, &vg->fid->metadata_areas_in_use) {
                if (!mda->ops->vg_write) {
@@ -2533,6 +2692,7 @@ static int _vg_commit_mdas(struct volume_group *vg)
                /* Update cache first time we succeed */
                if (!failed && !cache_updated) {
                        lvmcache_update_vg(vg, 0);
+                       // lvmetad_vg_commit(vg);
                        cache_updated = 1;
                }
        }
@@ -2544,17 +2704,21 @@ int vg_commit(struct volume_group *vg)
 {
        int cache_updated = 0;
 
-       if (!vgname_is_locked(vg->name)) {
+       if (!lvmcache_vgname_is_locked(vg->name)) {
                log_error(INTERNAL_ERROR "Attempt to write new VG metadata "
                          "without locking %s", vg->name);
                return cache_updated;
        }
 
+       if (!lvmetad_vg_update(vg))
+               return 0;
+
        cache_updated = _vg_commit_mdas(vg);
 
        if (cache_updated) {
                /* Instruct remote nodes to upgrade cached metadata. */
-               remote_commit_cached_metadata(vg);
+               if (!remote_commit_cached_metadata(vg))
+                       stack; // FIXME: What should we do?
                /*
                 * We need to clear old_name after a successful commit.
                 * The volume_group structure could be reused later.
@@ -2572,7 +2736,7 @@ int vg_commit(struct volume_group *vg)
 }
 
 /* Don't commit any pending changes */
-int vg_revert(struct volume_group *vg)
+void vg_revert(struct volume_group *vg)
 {
        struct metadata_area *mda;
 
@@ -2587,70 +2751,70 @@ int vg_revert(struct volume_group *vg)
                log_error("Attempt to drop cached metadata failed "
                          "after reverted update for VG %s.", vg->name);
 
-       remote_revert_cached_metadata(vg);
+       if (!remote_revert_cached_metadata(vg))
+               stack; // FIXME: What should we do?
+}
+
+struct _vg_read_orphan_baton {
+       struct volume_group *vg;
+       int warnings;
+};
+
+static int _vg_read_orphan_pv(struct lvmcache_info *info, void *baton)
+{
+       struct _vg_read_orphan_baton *b = baton;
+       struct physical_volume *pv = NULL;
+       struct pv_list *pvl;
 
+       if (!(pv = _pv_read(b->vg->cmd, b->vg->vgmem, dev_name(lvmcache_device(info)),
+                           b->vg->fid, b->warnings, 0))) {
+               stack;
+               return 1;
+       }
+
+       if (!(pvl = dm_pool_zalloc(b->vg->vgmem, sizeof(*pvl)))) {
+               log_error("pv_list allocation failed");
+               free_pv_fid(pv);
+               return 0;
+       }
+       pvl->pv = pv;
+       add_pvl_to_vgs(b->vg, pvl);
        return 1;
 }
 
-/* Make orphan PVs look like a VG */
+/* Make orphan PVs look like a VG. */
 static struct volume_group *_vg_read_orphans(struct cmd_context *cmd,
                                             int warnings,
                                             const char *orphan_vgname)
 {
+       const struct format_type *fmt;
        struct lvmcache_vginfo *vginfo;
-       struct lvmcache_info *info;
+       struct volume_group *vg = NULL;
+       struct _vg_read_orphan_baton baton;
        struct pv_list *pvl;
-       struct volume_group *vg;
-       struct physical_volume *pv;
-       struct dm_pool *mem;
 
        lvmcache_label_scan(cmd, 0);
+       lvmcache_seed_infos_from_lvmetad(cmd);
 
-       if (!(vginfo = vginfo_from_vgname(orphan_vgname, NULL)))
+       if (!(vginfo = lvmcache_vginfo_from_vgname(orphan_vgname, NULL)))
                return_NULL;
 
-       if (!(mem = dm_pool_create("vg_read orphan", VG_MEMPOOL_CHUNK)))
+       if (!(fmt = lvmcache_fmt_from_vgname(cmd, orphan_vgname, NULL, 0)))
                return_NULL;
 
-       if (!(vg = dm_pool_zalloc(mem, sizeof(*vg)))) {
-               log_error("vg allocation failed");
-               goto bad;
-       }
+       vg = fmt->orphan_vg;
+       dm_list_iterate_items(pvl, &vg->pvs)
+               pv_set_fid(pvl->pv, NULL);
        dm_list_init(&vg->pvs);
-       dm_list_init(&vg->lvs);
-       dm_list_init(&vg->tags);
-       dm_list_init(&vg->removed_pvs);
-       vg->vgmem = mem;
-       vg->cmd = cmd;
-       if (!(vg->name = dm_pool_strdup(mem, orphan_vgname))) {
-               log_error("vg name allocation failed");
-               goto bad;
-       }
+       vg->pv_count = 0;
 
-       /* create format instance with appropriate metadata area */
-       if (!(vg->fid = vginfo->fmt->ops->create_instance(vginfo->fmt,
-                                                         orphan_vgname, NULL,
-                                                         NULL))) {
-               log_error("Failed to create format instance");
-               goto bad;
-       }
+       baton.warnings = warnings;
+       baton.vg = vg;
 
-       dm_list_iterate_items(info, &vginfo->infos) {
-               if (!(pv = _pv_read(cmd, mem, dev_name(info->dev), NULL, NULL, warnings, 0))) {
-                       continue;
-               }
-               if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl)))) {
-                       log_error("pv_list allocation failed");
-                       goto bad;
-               }
-               pvl->pv = pv;
-               add_pvl_to_vgs(vg, pvl);
-       }
+       if (!lvmcache_foreach_pv(vginfo, _vg_read_orphan_pv, &baton))
+               return_NULL;
 
        return vg;
-bad:
-       dm_pool_destroy(mem);
-       return NULL;
 }
 
 static int _update_pv_list(struct dm_pool *pvmem, struct dm_list *all_pvs, struct volume_group *vg)
@@ -2679,6 +2843,22 @@ static int _update_pv_list(struct dm_pool *pvmem, struct dm_list *all_pvs, struc
        return 1;
 }
 
+static void _free_pv_list(struct dm_list *all_pvs)
+{
+       struct pv_list *pvl;
+
+       dm_list_iterate_items(pvl, all_pvs)
+               pvl->pv->fid->fmt->ops->destroy_instance(pvl->pv->fid);
+}
+
+static void _destroy_fid(struct format_instance **fid)
+{
+       if (*fid) {
+               (*fid)->fmt->ops->destroy_instance(*fid);
+               *fid = NULL;
+       }
+}
+
 int vg_missing_pv_count(const struct volume_group *vg)
 {
        int ret = 0;
@@ -2717,6 +2897,15 @@ static void check_reappeared_pv(struct volume_group *correct_vg,
                                         "on it, remove volumes and consider vgreduce --removemissing.");
                }
 }
+
+static int _check_mda_in_use(struct metadata_area *mda, void *_in_use)
+{
+       int *in_use = _in_use;
+       if (!mda_is_ignored(mda))
+               *in_use = 1;
+       return 1;
+}
+
 /* Caller sets consistent to 1 if it's safe for vg_read_internal to correct
  * inconsistent metadata on disk (i.e. the VG write lock is held).
  * This guarantees only consistent metadata is returned.
@@ -2727,6 +2916,9 @@ static void check_reappeared_pv(struct volume_group *correct_vg,
  * If precommitted is set, use precommitted metadata if present.
  *
  * Either of vgname or vgid may be NULL.
+ *
+ * Note: vginfo structs must not be held or used as parameters
+ *       across the call to this function.
  */
 static struct volume_group *_vg_read(struct cmd_context *cmd,
                                     const char *vgname,
@@ -2734,7 +2926,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
                                     int warnings, 
                                     int *consistent, unsigned precommitted)
 {
-       struct format_instance *fid;
+       struct format_instance *fid = NULL;
+       struct format_instance_ctx fic;
        const struct format_type *fmt;
        struct volume_group *vg, *correct_vg = NULL;
        struct metadata_area *mda;
@@ -2742,14 +2935,15 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
        int inconsistent = 0;
        int inconsistent_vgid = 0;
        int inconsistent_pvs = 0;
-       int inconsistent_seqno = 0;
        int inconsistent_mdas = 0;
+       int inconsistent_mda_count = 0;
        unsigned use_precommitted = precommitted;
        unsigned saved_handles_missing_pvs = cmd->handles_missing_pvs;
        struct dm_list *pvids;
        struct pv_list *pvl, *pvl2;
        struct dm_list all_pvs;
        char uuid[64] __attribute__((aligned(8)));
+       unsigned seqno = 0;
 
        if (is_orphan_vg(vgname)) {
                if (use_precommitted) {
@@ -2761,71 +2955,82 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
                return _vg_read_orphans(cmd, warnings, vgname);
        }
 
+       if (lvmetad_active() && !use_precommitted) {
+               *consistent = 1;
+               return lvmcache_get_vg(cmd, vgname, vgid, precommitted);
+       }
+
        /*
         * If cached metadata was inconsistent and *consistent is set
         * then repair it now.  Otherwise just return it.
         * Also return if use_precommitted is set due to the FIXME in
         * the missing PV logic below.
         */
-       if ((correct_vg = lvmcache_get_vg(vgid, precommitted)) &&
-           (use_precommitted || !*consistent || !(correct_vg->status & INCONSISTENT_VG))) {
-               if (!(correct_vg->status & INCONSISTENT_VG))
-                       *consistent = 1;
-               else    /* Inconsistent but we can't repair it */
-                       correct_vg->status &= ~INCONSISTENT_VG;
-
-               if (vg_missing_pv_count(correct_vg)) {
-                       log_verbose("There are %d physical volumes missing.",
-                                   vg_missing_pv_count(correct_vg));
-                       vg_mark_partial_lvs(correct_vg);
-               }
+       if ((correct_vg = lvmcache_get_vg(cmd, vgname, vgid, precommitted)) &&
+           (use_precommitted || !*consistent)) {
+               *consistent = 1;
                return correct_vg;
        } else {
-               free_vg(correct_vg);
+               if (correct_vg && correct_vg->seqno > seqno)
+                       seqno = correct_vg->seqno;
+               release_vg(correct_vg);
                correct_vg = NULL;
        }
 
+
        /* Find the vgname in the cache */
        /* If it's not there we must do full scan to be completely sure */
-       if (!(fmt = fmt_from_vgname(vgname, vgid, 1))) {
+       if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 1))) {
                lvmcache_label_scan(cmd, 0);
-               if (!(fmt = fmt_from_vgname(vgname, vgid, 1))) {
+               if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 1))) {
                        /* Independent MDAs aren't supported under low memory */
-                       if (!cmd->independent_metadata_areas && memlock())
+                       if (!cmd->independent_metadata_areas && critical_section())
                                return_NULL;
                        lvmcache_label_scan(cmd, 2);
-                       if (!(fmt = fmt_from_vgname(vgname, vgid, 0)))
+                       if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 0)))
                                return_NULL;
                }
        }
 
        /* Now determine the correct vgname if none was supplied */
-       if (!vgname && !(vgname = vgname_from_vgid(cmd->mem, vgid)))
+       if (!vgname && !(vgname = lvmcache_vgname_from_vgid(cmd->mem, vgid)))
                return_NULL;
 
        if (use_precommitted && !(fmt->features & FMT_PRECOMMIT))
                use_precommitted = 0;
 
        /* create format instance with appropriate metadata area */
-       if (!(fid = fmt->ops->create_instance(fmt, vgname, vgid, NULL))) {
+       fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
+       fic.context.vg_ref.vg_name = vgname;
+       fic.context.vg_ref.vg_id = vgid;
+       if (!(fid = fmt->ops->create_instance(fmt, &fic))) {
                log_error("Failed to create format instance");
                return NULL;
        }
 
        /* Store pvids for later so we can check if any are missing */
-       if (!(pvids = lvmcache_get_pvids(cmd, vgname, vgid)))
+       if (!(pvids = lvmcache_get_pvids(cmd, vgname, vgid))) {
+               _destroy_fid(&fid);
                return_NULL;
+       }
 
+       /*
+        * We use the fid globally here so prevent the release_vg
+        * call to destroy the fid - we may want to reuse it!
+        */
+       fid->ref_count++;
        /* Ensure contents of all metadata areas match - else do recovery */
+       inconsistent_mda_count=0;
        dm_list_iterate_items(mda, &fid->metadata_areas_in_use) {
+
                if ((use_precommitted &&
                     !(vg = mda->ops->vg_read_precommit(fid, vgname, mda))) ||
                    (!use_precommitted &&
-                    !(vg = mda->ops->vg_read(fid, vgname, mda)))) {
+                    !(vg = mda->ops->vg_read(fid, vgname, mda, 0)))) {
                        inconsistent = 1;
-                       free_vg(vg);
                        continue;
                }
+
                if (!correct_vg) {
                        correct_vg = vg;
                        continue;
@@ -2837,22 +3042,31 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
                                log_very_verbose("Not repairing VG %s metadata seqno (%d != %d) "
                                                  "as global/metadata_read_only is set.",
                                                  vgname, vg->seqno, correct_vg->seqno);
-                       else {
+                       else
                                inconsistent = 1;
-                               inconsistent_seqno = 1;
-                       }
+
                        if (vg->seqno > correct_vg->seqno) {
-                               free_vg(correct_vg);
+                               release_vg(correct_vg);
                                correct_vg = vg;
+                       } else {
+                               mda->status |= MDA_INCONSISTENT;
+                               ++inconsistent_mda_count;
                        }
                }
 
                if (vg != correct_vg)
-                       free_vg(vg);
+                       release_vg(vg);
        }
+       fid->ref_count--;
 
        /* Ensure every PV in the VG was in the cache */
        if (correct_vg) {
+               /*
+                * Update the seqno from the cache, for the benefit of
+                * retro-style metadata formats like LVM1.
+                */
+               // correct_vg->seqno = seqno > correct_vg->seqno ? seqno : correct_vg->seqno;
+
                /*
                 * If the VG has PVs without mdas, or ignored mdas, they may
                 * still be orphans in the cache: update the cache state here,
@@ -2874,15 +3088,17 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
                                 * Check it's an orphan without metadata area
                                 * not ignored.
                                 */
-                               if (!(info = info_from_pvid(pvl->pv->dev->pvid, 1)) ||
-                                  !info->vginfo || !is_orphan_vg(info->vginfo->vgname)) {
+                               if (!(info = lvmcache_info_from_pvid(pvl->pv->dev->pvid, 1)) ||
+                                   !lvmcache_is_orphan(info)) {
                                        inconsistent_pvs = 1;
                                        break;
                                }
-                               if (dm_list_size(&info->mdas)) {
-                                       if (!fid_add_mdas(fid, &info->mdas))
+                               if (lvmcache_mda_count(info)) {
+                                       if (!lvmcache_fid_add_mdas_pv(info, fid)) {
+                                               release_vg(correct_vg);
                                                return_NULL;
-                                        
+                                       }
+
                                        log_debug("Empty mda found for VG %s.", vgname);
 
                                        if (inconsistent_mdas)
@@ -2892,11 +3108,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
                                         * If any newly-added mdas are in-use then their
                                         * metadata needs updating.
                                         */
-                                       dm_list_iterate_items(mda, &info->mdas)
-                                               if (!mda_is_ignored(mda)) {
-                                                       inconsistent_mdas = 1;
-                                                       break;
-                                               }
+                                       lvmcache_foreach_mda(info, _check_mda_in_use,
+                                                            &inconsistent_mdas);
                                }
                        }
 
@@ -2910,20 +3123,23 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
                                 */
                                lvmcache_update_vg(correct_vg, correct_vg->status & PRECOMMITTED);
 
-                               if (!(pvids = lvmcache_get_pvids(cmd, vgname, vgid)))
+                               if (!(pvids = lvmcache_get_pvids(cmd, vgname, vgid))) {
+                                       release_vg(correct_vg);
                                        return_NULL;
+                               }
                        }
                }
 
+               fid->ref_count++;
                if (dm_list_size(&correct_vg->pvs) !=
                    dm_list_size(pvids) + vg_missing_pv_count(correct_vg)) {
                        log_debug("Cached VG %s had incorrect PV list",
                                  vgname);
 
-                       if (memlock())
+                       if (critical_section())
                                inconsistent = 1;
                        else {
-                               free_vg(correct_vg);
+                               release_vg(correct_vg);
                                correct_vg = NULL;
                        }
                } else dm_list_iterate_items(pvl, &correct_vg->pvs) {
@@ -2932,61 +3148,79 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
                        if (!str_list_match_item(pvids, pvl->pv->dev->pvid)) {
                                log_debug("Cached VG %s had incorrect PV list",
                                          vgname);
-                               free_vg(correct_vg);
+                               release_vg(correct_vg);
                                correct_vg = NULL;
                                break;
                        }
                }
 
                if (correct_vg && inconsistent_mdas) {
-                       free_vg(correct_vg);
+                       release_vg(correct_vg);
                        correct_vg = NULL;
                }
+               fid->ref_count--;
        }
 
        dm_list_init(&all_pvs);
 
        /* Failed to find VG where we expected it - full scan and retry */
        if (!correct_vg) {
+               /*
+                * Free outstanding format instance that remained unassigned
+                * from previous step where we tried to get the "correct_vg",
+                * but we failed to do so (so there's a dangling fid now).
+                */
+               _destroy_fid(&fid);
+
                inconsistent = 0;
 
                /* Independent MDAs aren't supported under low memory */
-               if (!cmd->independent_metadata_areas && memlock())
+               if (!cmd->independent_metadata_areas && critical_section())
                        return_NULL;
                lvmcache_label_scan(cmd, 2);
-               if (!(fmt = fmt_from_vgname(vgname, vgid, 0)))
+               if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 0)))
                        return_NULL;
 
                if (precommitted && !(fmt->features & FMT_PRECOMMIT))
                        use_precommitted = 0;
 
                /* create format instance with appropriate metadata area */
-               if (!(fid = fmt->ops->create_instance(fmt, vgname, vgid, NULL))) {
+               fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
+               fic.context.vg_ref.vg_name = vgname;
+               fic.context.vg_ref.vg_id = vgid;
+               if (!(fid = fmt->ops->create_instance(fmt, &fic))) {
                        log_error("Failed to create format instance");
                        return NULL;
                }
 
+               /*
+                * We use the fid globally here so prevent the release_vg
+                * call to destroy the fid - we may want to reuse it!
+               */
+               fid->ref_count++;
                /* Ensure contents of all metadata areas match - else recover */
+               inconsistent_mda_count=0;
                dm_list_iterate_items(mda, &fid->metadata_areas_in_use) {
                        if ((use_precommitted &&
                             !(vg = mda->ops->vg_read_precommit(fid, vgname,
                                                                mda))) ||
                            (!use_precommitted &&
-                            !(vg = mda->ops->vg_read(fid, vgname, mda)))) {
+                            !(vg = mda->ops->vg_read(fid, vgname, mda, 0)))) {
                                inconsistent = 1;
                                continue;
                        }
                        if (!correct_vg) {
                                correct_vg = vg;
                                if (!_update_pv_list(cmd->mem, &all_pvs, correct_vg)) {
-                                       free_vg(vg);
+                                       _free_pv_list(&all_pvs);
+                                       fid->ref_count--;
+                                       release_vg(vg);
                                        return_NULL;
                                }
                                continue;
                        }
 
-                       if (strncmp((char *)vg->id.uuid,
-                           (char *)correct_vg->id.uuid, ID_LEN)) {
+                       if (!id_equal(&vg->id, &correct_vg->id)) {
                                inconsistent = 1;
                                inconsistent_vgid = 1;
                        }
@@ -2998,64 +3232,89 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
                                        log_very_verbose("Not repairing VG %s metadata seqno (%d != %d) "
                                                          "as global/metadata_read_only is set.",
                                                          vgname, vg->seqno, correct_vg->seqno);
-                               else {
+                               else
                                        inconsistent = 1;
-                                       inconsistent_seqno = 1;
-                               }
+
                                if (!_update_pv_list(cmd->mem, &all_pvs, vg)) {
-                                       free_vg(vg);
-                                       free_vg(correct_vg);
+                                       _free_pv_list(&all_pvs);
+                                       fid->ref_count--;
+                                       release_vg(vg);
+                                       release_vg(correct_vg);
                                        return_NULL;
                                }
                                if (vg->seqno > correct_vg->seqno) {
-                                       free_vg(correct_vg);
+                                       release_vg(correct_vg);
                                        correct_vg = vg;
+                               } else {
+                                       mda->status |= MDA_INCONSISTENT;
+                                       ++inconsistent_mda_count;
                                }
                        }
 
                        if (vg != correct_vg)
-                               free_vg(vg);
+                               release_vg(vg);
                }
+               fid->ref_count--;
 
                /* Give up looking */
-               if (!correct_vg)
+               if (!correct_vg) {
+                       _free_pv_list(&all_pvs);
+                       _destroy_fid(&fid);
                        return_NULL;
+               }
        }
 
        /*
         * If there is no precommitted metadata, committed metadata
         * is read and stored in the cache even if use_precommitted is set
         */
-       lvmcache_update_vg(correct_vg, correct_vg->status & PRECOMMITTED &
-                          (inconsistent ? INCONSISTENT_VG : 0));
+       lvmcache_update_vg(correct_vg, (correct_vg->status & PRECOMMITTED));
 
        if (inconsistent) {
                /* FIXME Test should be if we're *using* precommitted metadata not if we were searching for it */
                if (use_precommitted) {
                        log_error("Inconsistent pre-commit metadata copies "
                                  "for volume group %s", vgname);
-                       /* FIXME: during repair, there is inconsistent flag set because some metadata areas
-                        * are missing (on missing PVs). Code should create list of missing PVs, compare it
-                        * with PV marked missing in metadata and if equals, use it as consistent vg.
-                        * For now, return precommited metadata if remainng seq match here to allow
-                        * preloading table in suspend call.
+
+                       /*
+                        * Check whether all of the inconsistent MDAs were on
+                        * MISSING PVs -- in that case, we should be safe.
                         */
-                       if (!inconsistent_seqno) {
+                       dm_list_iterate_items(mda, &fid->metadata_areas_in_use) {
+                               if (mda->status & MDA_INCONSISTENT) {
+                                       log_debug("Checking inconsistent MDA: %s", dev_name(mda_get_device(mda)));
+                                       dm_list_iterate_items(pvl, &correct_vg->pvs) {
+                                               if (mda_get_device(mda) == pvl->pv->dev &&
+                                                   (pvl->pv->status & MISSING_PV))
+                                                       --inconsistent_mda_count;
+                                       }
+                               }
+                       }
+
+                       if (inconsistent_mda_count < 0)
+                               log_error(INTERNAL_ERROR "Too many inconsistent MDAs.");
+
+                       if (!inconsistent_mda_count) {
                                *consistent = 0;
+                               _free_pv_list(&all_pvs);
                                return correct_vg;
                        }
-                       free_vg(correct_vg);
+                       _free_pv_list(&all_pvs);
+                       release_vg(correct_vg);
                        return NULL;
                }
 
-               if (!*consistent)
+               if (!*consistent) {
+                       _free_pv_list(&all_pvs);
                        return correct_vg;
+               }
 
                /* Don't touch if vgids didn't match */
                if (inconsistent_vgid) {
                        log_error("Inconsistent metadata UUIDs found for "
                                  "volume group %s", vgname);
                        *consistent = 0;
+                       _free_pv_list(&all_pvs);
                        return correct_vg;
                }
 
@@ -3072,7 +3331,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
                cmd->handles_missing_pvs = 1;
                if (!vg_write(correct_vg)) {
                        log_error("Automatic metadata correction failed");
-                       free_vg(correct_vg);
+                       _free_pv_list(&all_pvs);
+                       release_vg(correct_vg);
                        cmd->handles_missing_pvs = saved_handles_missing_pvs;
                        return NULL;
                }
@@ -3081,7 +3341,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
                if (!vg_commit(correct_vg)) {
                        log_error("Automatic metadata correction commit "
                                  "failed");
-                       free_vg(correct_vg);
+                       release_vg(correct_vg);
                        return NULL;
                }
 
@@ -3091,13 +3351,15 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
                                        goto next_pv;
                        }
                        if (!id_write_format(&pvl->pv->id, uuid, sizeof(uuid))) {
-                               free_vg(correct_vg);
+                               _free_pv_list(&all_pvs);
+                               release_vg(correct_vg);
                                return_NULL;
                        }
                        log_error("Removing PV %s (%s) that no longer belongs to VG %s",
                                  pv_dev_name(pvl->pv), uuid, correct_vg->name);
                        if (!pv_write_orphan(cmd, pvl->pv)) {
-                               free_vg(correct_vg);
+                               _free_pv_list(&all_pvs);
+                               release_vg(correct_vg);
                                return_NULL;
                        }
 
@@ -3108,10 +3370,12 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
                }
        }
 
+       _free_pv_list(&all_pvs);
+
        if (vg_missing_pv_count(correct_vg)) {
                log_verbose("There are %d physical volumes missing.",
                            vg_missing_pv_count(correct_vg));
-               vg_mark_partial_lvs(correct_vg);
+               vg_mark_partial_lvs(correct_vg, 1);
        }
 
        if ((correct_vg->status & PVMOVE) && !pvmove_mode()) {
@@ -3119,7 +3383,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
                          "volume group %s", correct_vg->name);
                log_error("Please restore the metadata by running "
                          "vgcfgrestore.");
-               free_vg(correct_vg);
+               release_vg(correct_vg);
                return NULL;
        }
 
@@ -3139,7 +3403,7 @@ struct volume_group *vg_read_internal(struct cmd_context *cmd, const char *vgnam
        if (!check_pv_segments(vg)) {
                log_error(INTERNAL_ERROR "PV segments corrupted in %s.",
                          vg->name);
-               free_vg(vg);
+               release_vg(vg);
                return NULL;
        }
 
@@ -3147,7 +3411,7 @@ struct volume_group *vg_read_internal(struct cmd_context *cmd, const char *vgnam
                if (!check_lv_segments(lvl->lv, 0)) {
                        log_error(INTERNAL_ERROR "LV segments corrupted in %s.",
                                  lvl->lv->name);
-                       free_vg(vg);
+                       release_vg(vg);
                        return NULL;
                }
        }
@@ -3159,7 +3423,7 @@ struct volume_group *vg_read_internal(struct cmd_context *cmd, const char *vgnam
                if (!check_lv_segments(lvl->lv, 1)) {
                        log_error(INTERNAL_ERROR "LV segments corrupted in %s.",
                                  lvl->lv->name);
-                       free_vg(vg);
+                       release_vg(vg);
                        return NULL;
                }
        }
@@ -3167,18 +3431,13 @@ struct volume_group *vg_read_internal(struct cmd_context *cmd, const char *vgnam
        return vg;
 }
 
-void free_vg(struct volume_group *vg)
+void free_pv_fid(struct physical_volume *pv)
 {
-       if (!vg)
-               return;
-
-       if (vg->cmd && vg->vgmem == vg->cmd->mem) {
-               log_error(INTERNAL_ERROR "global memory pool used for VG %s",
-                         vg->name);
+       if (!pv)
                return;
-       }
 
-       dm_pool_destroy(vg->vgmem);
+       if (pv->fid)
+               pv->fid->fmt->ops->destroy_instance(pv->fid);
 }
 
 /* This is only called by lv_from_lvid, which is only called from
@@ -3192,26 +3451,24 @@ static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
        const char *vgname;
        struct dm_list *vgnames;
        struct volume_group *vg;
-       struct lvmcache_vginfo *vginfo;
        struct str_list *strl;
        int consistent = 0;
 
        /* Is corresponding vgname already cached? */
-       if ((vginfo = vginfo_from_vgid(vgid)) &&
-           vginfo->vgname && !is_orphan_vg(vginfo->vgname)) {
+       if (lvmcache_vgid_is_cached(vgid)) {
                if ((vg = _vg_read(cmd, NULL, vgid, 1,
                                   &consistent, precommitted)) &&
-                   !strncmp((char *)vg->id.uuid, vgid, ID_LEN)) {
+                   id_equal(&vg->id, (const struct id *)vgid)) {
                        if (!consistent)
                                log_error("Volume group %s metadata is "
                                          "inconsistent", vg->name);
                        return vg;
                }
-               free_vg(vg);
+               release_vg(vg);
        }
 
        /* Mustn't scan if memory locked: ensure cache gets pre-populated! */
-       if (memlock())
+       if (critical_section())
                return_NULL;
 
        /* FIXME Need a genuine read by ID here - don't vg_read_internal by name! */
@@ -3232,16 +3489,16 @@ static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
                consistent = 0;
                if ((vg = _vg_read(cmd, vgname, vgid, 1, &consistent,
                                   precommitted)) &&
-                   !strncmp((char *)vg->id.uuid, vgid, ID_LEN)) {
+                   id_equal(&vg->id, (const struct id *)vgid)) {
                        if (!consistent) {
                                log_error("Volume group %s metadata is "
                                          "inconsistent", vgname);
-                               free_vg(vg);
+                               release_vg(vg);
                                return NULL;
                        }
                        return vg;
                }
-               free_vg(vg);
+               release_vg(vg);
        }
 
        return NULL;
@@ -3275,7 +3532,7 @@ struct logical_volume *lv_from_lvid(struct cmd_context *cmd, const char *lvid_s,
 
        return lvl->lv;
 out:
-       free_vg(vg);
+       release_vg(vg);
        return NULL;
 }
 
@@ -3289,7 +3546,7 @@ const char *find_vgname_from_pvid(struct cmd_context *cmd,
        vgname = lvmcache_vgname_from_pvid(cmd, pvid);
 
        if (is_orphan_vg(vgname)) {
-               if (!(info = info_from_pvid(pvid, 0))) {
+               if (!(info = lvmcache_info_from_pvid(pvid, 0))) {
                        return_NULL;
                }
                /*
@@ -3299,7 +3556,7 @@ const char *find_vgname_from_pvid(struct cmd_context *cmd,
                 * Detecting this means checking every VG by scanning
                 * every PV on the system.
                 */
-               if (mdas_empty_or_ignored(&info->mdas)) {
+               if (lvmcache_uncertain_ownership(info)) {
                        if (!scan_vgs_for_pvs(cmd, 1)) {
                                log_error("Rescan for PVs without "
                                          "metadata areas failed.");
@@ -3321,7 +3578,7 @@ const char *find_vgname_from_pvname(struct cmd_context *cmd,
 {
        const char *pvid;
 
-       pvid = pvid_from_devname(cmd, pvname);
+       pvid = lvmcache_pvid_from_devname(cmd, pvname);
        if (!pvid)
                /* Not a PV */
                return NULL;
@@ -3345,38 +3602,54 @@ const char *find_vgname_from_pvname(struct cmd_context *cmd,
  *   FIXME - liblvm todo - make into function that returns handle
  */
 struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
-                               struct dm_list *mdas, uint64_t *label_sector,
-                               int warnings, int scan_label_only)
+                               int warnings,
+                               int scan_label_only)
 {
-       return _pv_read(cmd, cmd->mem, pv_name, mdas, label_sector, warnings, scan_label_only);
+       return _pv_read(cmd, cmd->mem, pv_name, NULL, warnings, scan_label_only);
 }
 
 /* FIXME Use label functions instead of PV functions */
 static struct physical_volume *_pv_read(struct cmd_context *cmd,
                                        struct dm_pool *pvmem,
                                        const char *pv_name,
-                                       struct dm_list *mdas,
-                                       uint64_t *label_sector,
+                                       struct format_instance *fid,
                                        int warnings, int scan_label_only)
 {
        struct physical_volume *pv;
        struct label *label;
        struct lvmcache_info *info;
        struct device *dev;
+       const struct format_type *fmt;
+       int found;
 
        if (!(dev = dev_cache_get(pv_name, cmd->filter)))
                return_NULL;
 
-       if (!(label_read(dev, &label, UINT64_C(0)))) {
-               if (warnings)
-                       log_error("No physical volume label read from %s",
-                                 pv_name);
-               return NULL;
+       if (lvmetad_active()) {
+               info = lvmcache_info_from_pvid(dev->pvid, 0);
+               if (!info) {
+                       if (!lvmetad_pv_lookup_by_dev(cmd, dev, &found))
+                               return_NULL;
+                       if (!found) {
+                               if (warnings)
+                                       log_error("No physical volume found in lvmetad cache for %s",
+                                                 pv_name);
+                               return NULL;
+                       }
+               }
+               info = lvmcache_info_from_pvid(dev->pvid, 0);
+               label = lvmcache_get_label(info);
+       } else {
+               if (!(label_read(dev, &label, UINT64_C(0)))) {
+                       if (warnings)
+                               log_error("No physical volume label read from %s",
+                                         pv_name);
+                       return NULL;
+               }
+               info = (struct lvmcache_info *) label->info;
        }
 
-       info = (struct lvmcache_info *) label->info;
-       if (label_sector && *label_sector)
-               *label_sector = label->sector;
+       fmt = lvmcache_fmt(info);
 
        pv = _alloc_pv(pvmem, dev);
        if (!pv) {
@@ -3384,9 +3657,10 @@ static struct physical_volume *_pv_read(struct cmd_context *cmd,
                return NULL;
        }
 
+       pv->label_sector = label->sector;
+
        /* FIXME Move more common code up here */
-       if (!(info->fmt->ops->pv_read(info->fmt, pv_name, pv, mdas,
-             scan_label_only))) {
+       if (!(lvmcache_fmt(info)->ops->pv_read(lvmcache_fmt(info), pv_name, pv, scan_label_only))) {
                log_error("Failed to read existing physical volume '%s'",
                          pv_name);
                goto bad;
@@ -3398,9 +3672,17 @@ static struct physical_volume *_pv_read(struct cmd_context *cmd,
        if (!alloc_pv_segment_whole_pv(pvmem, pv))
                goto_bad;
 
+       if (fid)
+               lvmcache_fid_add_mdas(info, fid, (const char *) &pv->id, ID_LEN);
+       else {
+               lvmcache_fid_add_mdas(info, fmt->orphan_vg->fid, (const char *) &pv->id, ID_LEN);
+               pv_set_fid(pv, fmt->orphan_vg->fid);
+       }
+
        return pv;
 bad:
-       _free_pv(pvmem, pv);
+       free_pv_fid(pv);
+       dm_pool_free(pvmem, pv);
        return NULL;
 }
 
@@ -3452,7 +3734,7 @@ static int _get_pvs(struct cmd_context *cmd, int warnings, struct dm_list **pvsl
                if (!vgid)
                        continue;       /* FIXME Unnecessary? */
                consistent = 0;
-               if (!(vgname = vgname_from_vgid(NULL, vgid))) {
+               if (!(vgname = lvmcache_vgname_from_vgid(NULL, vgid))) {
                        stack;
                        continue;
                }
@@ -3469,12 +3751,12 @@ static int _get_pvs(struct cmd_context *cmd, int warnings, struct dm_list **pvsl
                        dm_list_iterate_items(pvl, &vg->pvs) {
                                if (!(pvl_copy = _copy_pvl(cmd->mem, pvl))) {
                                        log_error("PV list allocation failed");
-                                       free_vg(vg);
+                                       release_vg(vg);
                                        return 0;
                                }
                                dm_list_add(results, &pvl_copy->list);
                        }
-               free_vg(vg);
+               release_vg(vg);
        }
        init_pvmove(old_pvmove);
 
@@ -3502,21 +3784,31 @@ int scan_vgs_for_pvs(struct cmd_context *cmd, int warnings)
 }
 
 int pv_write(struct cmd_context *cmd __attribute__((unused)),
-            struct physical_volume *pv,
-            struct dm_list *mdas, int64_t label_sector)
+            struct physical_volume *pv, int allow_non_orphan)
 {
        if (!pv->fmt->ops->pv_write) {
                log_error("Format does not support writing physical volumes");
                return 0;
        }
 
-       if (!is_orphan_vg(pv->vg_name) || pv->pe_alloc_count) {
+       /*
+        * FIXME: Try to remove this restriction. This requires checking
+        *        that the PV and the VG are in a consistent state. We need
+        *        to provide some revert mechanism since PV label together
+        *        with VG metadata write is not atomic.
+        */
+       if (!allow_non_orphan &&
+           (!is_orphan_vg(pv->vg_name) || pv->pe_alloc_count)) {
                log_error("Assertion failed: can't _pv_write non-orphan PV "
                          "(in VG %s)", pv->vg_name);
                return 0;
        }
 
-       if (!pv->fmt->ops->pv_write(pv->fmt, pv, mdas, label_sector))
+       if (!pv->fmt->ops->pv_write(pv->fmt, pv))
+               return_0;
+
+       if (!lvmetad_pv_found(&pv->id, pv->dev, pv->fmt, pv->label_sector,
+                             NULL, NULL))
                return_0;
 
        return 1;
@@ -3535,7 +3827,7 @@ int pv_write_orphan(struct cmd_context *cmd, struct physical_volume *pv)
                return 0;
        }
 
-       if (!pv_write(cmd, pv, NULL, INT64_C(-1))) {
+       if (!pv_write(cmd, pv, 0)) {
                log_error("Failed to clear metadata from physical "
                          "volume \"%s\" after removal from \"%s\"",
                          pv_dev_name(pv), old_vg_name);
@@ -3559,6 +3851,21 @@ int is_orphan_vg(const char *vg_name)
        return (vg_name && !strncmp(vg_name, ORPHAN_PREFIX, sizeof(ORPHAN_PREFIX) - 1)) ? 1 : 0;
 }
 
+/*
+ * Exclude pseudo VG names used for locking.
+ */
+int is_real_vg(const char *vg_name)
+{
+       return (vg_name && *vg_name != '#');
+}
+
+static int _analyze_mda(struct metadata_area *mda, void *baton)
+{
+       const struct format_type *fmt = baton;
+       mda->ops->pv_analyze_mda(fmt, mda);
+       return 1;
+}
+
 /*
  * Returns:
  *  0 - fail
@@ -3569,7 +3876,6 @@ int pv_analyze(struct cmd_context *cmd, const char *pv_name,
 {
        struct label *label;
        struct device *dev;
-       struct metadata_area *mda;
        struct lvmcache_info *info;
 
        dev = dev_cache_get(pv_name, cmd->filter);
@@ -3588,15 +3894,14 @@ int pv_analyze(struct cmd_context *cmd, const char *pv_name,
                return 0;
        }
 
-       log_print("Found label on %s, sector %"PRIu64", type=%s",
+       log_print("Found label on %s, sector %"PRIu64", type=%.8s",
                  pv_name, label->sector, label->type);
 
        /*
         * Next, loop through metadata areas
         */
        info = label->info;
-       dm_list_iterate_items(mda, &info->mdas)
-               mda->ops->pv_analyze_mda(info->fmt, mda);
+       lvmcache_foreach_mda(info, _analyze_mda, (void *)lvmcache_fmt(info));
 
        return 1;
 }
@@ -3677,7 +3982,7 @@ static struct volume_group *_recover_vg(struct cmd_context *cmd,
                return_NULL;
 
        if (!consistent) {
-               free_vg(vg);
+               release_vg(vg);
                return_NULL;
        }
 
@@ -3714,7 +4019,7 @@ static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const cha
                return NULL;
        }
 
-       already_locked = vgname_is_locked(vg_name);
+       already_locked = lvmcache_vgname_is_locked(vg_name);
 
        if (!already_locked && !(misc_flags & READ_WITHOUT_LOCK) &&
            !lock_vol(cmd, vg_name, lock_flags)) {
@@ -3738,18 +4043,18 @@ static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const cha
                log_error("Volume group \"%s\" not found", vg_name);
 
                failure |= FAILED_NOTFOUND;
-               goto_bad;
+               goto bad;
        }
 
        if (vg_is_clustered(vg) && !locking_is_clustered()) {
                log_error("Skipping clustered volume group %s", vg->name);
                failure |= FAILED_CLUSTERED;
-               goto_bad;
+               goto bad;
        }
 
        /* consistent == 0 when VG is not found, but failed == FAILED_NOTFOUND */
        if (!consistent && !failure) {
-               free_vg(vg);
+               release_vg(vg);
                if (!(vg = _recover_vg(cmd, vg_name, vgid))) {
                        log_error("Recovery of volume group \"%s\" failed.",
                                  vg_name);
@@ -3878,20 +4183,20 @@ uint32_t vg_lock_newname(struct cmd_context *cmd, const char *vgname)
 
        /* Find the vgname in the cache */
        /* If it's not there we must do full scan to be completely sure */
-       if (!fmt_from_vgname(vgname, NULL, 1)) {
+       if (!lvmcache_fmt_from_vgname(cmd, vgname, NULL, 1)) {
                lvmcache_label_scan(cmd, 0);
-               if (!fmt_from_vgname(vgname, NULL, 1)) {
+               if (!lvmcache_fmt_from_vgname(cmd, vgname, NULL, 1)) {
                        /* Independent MDAs aren't supported under low memory */
-                       if (!cmd->independent_metadata_areas && memlock()) {
+                       if (!cmd->independent_metadata_areas && critical_section()) {
                                /*
                                 * FIXME: Disallow calling this function if
-                                * memlock() is true.
+                                * critical_section() is true.
                                 */
                                unlock_vg(cmd, vgname);
                                return FAILED_LOCKING;
                        }
                        lvmcache_label_scan(cmd, 2);
-                       if (!fmt_from_vgname(vgname, NULL, 0)) {
+                       if (!lvmcache_fmt_from_vgname(cmd, vgname, NULL, 0)) {
                                /* vgname not found after scanning */
                                return SUCCESS;
                        }
@@ -3903,22 +4208,177 @@ uint32_t vg_lock_newname(struct cmd_context *cmd, const char *vgname)
        return FAILED_EXIST;
 }
 
-void fid_add_mda(struct format_instance *fid, struct metadata_area *mda)
+struct format_instance *alloc_fid(const struct format_type *fmt,
+                                 const struct format_instance_ctx *fic)
 {
+       struct dm_pool *mem;
+       struct format_instance *fid;
+
+       if (!(mem = dm_pool_create("format_instance", 1024)))
+               return_NULL;
+
+       if (!(fid = dm_pool_zalloc(mem, sizeof(*fid)))) {
+               log_error("Couldn't allocate format_instance object.");
+               goto bad;
+       }
+
+       fid->ref_count = 1;
+       fid->mem = mem;
+       fid->type = fic->type;
+       fid->fmt = fmt;
+
+       dm_list_init(&fid->metadata_areas_in_use);
+       dm_list_init(&fid->metadata_areas_ignored);
+
+       return fid;
+
+bad:
+       dm_pool_destroy(mem);
+       return NULL;
+}
+
+void pv_set_fid(struct physical_volume *pv,
+               struct format_instance *fid)
+{
+       if (fid == pv->fid)
+               return;
+
+       if (fid)
+               fid->ref_count++;
+
+       if (pv->fid)
+               pv->fid->fmt->ops->destroy_instance(pv->fid);
+
+       pv->fid = fid;
+}
+
+void vg_set_fid(struct volume_group *vg,
+                struct format_instance *fid)
+{
+       struct pv_list *pvl;
+
+       if (fid == vg->fid)
+               return;
+
+       if (fid)
+               fid->ref_count++;
+
+       dm_list_iterate_items(pvl, &vg->pvs)
+               pv_set_fid(pvl->pv, fid);
+
+       dm_list_iterate_items(pvl, &vg->removed_pvs)
+               pv_set_fid(pvl->pv, fid);
+
+       if (vg->fid)
+               vg->fid->fmt->ops->destroy_instance(vg->fid);
+
+       vg->fid = fid;
+}
+
+static int _convert_key_to_string(const char *key, size_t key_len,
+                                 unsigned sub_key, char *buf, size_t buf_len)
+{
+       memcpy(buf, key, key_len);
+       buf += key_len;
+       buf_len -= key_len;
+       if ((dm_snprintf(buf, buf_len, "_%u", sub_key) == -1))
+               return_0;
+
+       return 1;
+}
+
+int fid_add_mda(struct format_instance *fid, struct metadata_area *mda,
+                const char *key, size_t key_len, const unsigned sub_key)
+{
+       static char full_key[PATH_MAX];
+
        dm_list_add(mda_is_ignored(mda) ? &fid->metadata_areas_ignored :
-                                         &fid->metadata_areas_in_use, &mda->list);
+                                         &fid->metadata_areas_in_use, &mda->list);
+
+       /* Return if the mda is not supposed to be indexed. */
+       if (!key)
+               return 1;
+
+       /* Add metadata area to index. */
+       if (!_convert_key_to_string(key, key_len, sub_key,
+                                   full_key, sizeof(full_key)))
+               return_0;
+
+       if (!dm_hash_insert(fid->metadata_areas_index,
+                           full_key, mda)) {
+               log_error("Failed to hash mda.");
+               return 0;
+       }
+
+       return 1;
 }
 
-int fid_add_mdas(struct format_instance *fid, struct dm_list *mdas)
+int fid_add_mdas(struct format_instance *fid, struct dm_list *mdas,
+                const char *key, size_t key_len)
 {
        struct metadata_area *mda, *mda_new;
+       unsigned mda_index = 0;
 
        dm_list_iterate_items(mda, mdas) {
-               mda_new = mda_copy(fid->fmt->cmd->mem, mda);
+               mda_new = mda_copy(fid->mem, mda);
                if (!mda_new)
                        return_0;
-               fid_add_mda(fid, mda_new);
+               fid_remove_mda(fid, NULL, key, key_len, mda_index);
+               fid_add_mda(fid, mda_new, key, key_len, mda_index);
+               mda_index++;
+       }
+
+       return 1;
+}
+
+struct metadata_area *fid_get_mda_indexed(struct format_instance *fid,
+                                         const char *key, size_t key_len,
+                                         const unsigned sub_key)
+{
+       static char full_key[PATH_MAX];
+       struct metadata_area *mda = NULL;
+
+
+       if (!_convert_key_to_string(key, key_len, sub_key,
+                                   full_key, sizeof(full_key)))
+               return_NULL;
+       mda = (struct metadata_area *) dm_hash_lookup(fid->metadata_areas_index,
+                                                     full_key);
+
+       return mda;
+}
+
+int fid_remove_mda(struct format_instance *fid, struct metadata_area *mda,
+                  const char *key, size_t key_len, const unsigned sub_key)
+{
+       static char full_key[PATH_MAX];
+       struct metadata_area *mda_indexed = NULL;
+
+       /* At least one of mda or key must be specified. */
+       if (!mda && !key)
+               return 1;
+
+       if (key) {
+               /*
+                * If both mda and key specified, check given mda
+                * with what we find using the index and return
+                * immediately if these two do not match.
+                */
+               if (!(mda_indexed = fid_get_mda_indexed(fid, key, key_len, sub_key)) ||
+                    (mda && mda != mda_indexed))
+                       return 1;
+
+               mda = mda_indexed;
+
+               if (!_convert_key_to_string(key, key_len, sub_key,
+                                   full_key, sizeof(full_key)))
+                       return_0;
+
+               dm_hash_remove(fid->metadata_areas_index, full_key);
        }
+
+       dm_list_del(&mda->list);
+
        return 1;
 }
 
@@ -3978,6 +4438,13 @@ unsigned mda_locns_match(struct metadata_area *mda1, struct metadata_area *mda2)
        return mda1->ops->mda_locns_match(mda1, mda2);
 }
 
+struct device *mda_get_device(struct metadata_area *mda)
+{
+       if (!mda->ops->mda_get_device)
+               return NULL;
+       return mda->ops->mda_get_device(mda);
+}
+
 unsigned mda_is_ignored(struct metadata_area *mda)
 {
        return (mda->status & MDA_IGNORED);
@@ -4099,8 +4566,5 @@ char *tags_format_and_copy(struct dm_pool *mem, const struct dm_list *tags)
  */
 struct physical_volume *pv_by_path(struct cmd_context *cmd, const char *pv_name)
 {
-       struct dm_list mdas;
-
-       dm_list_init(&mdas);
-       return _pv_read(cmd, cmd->mem, pv_name, &mdas, NULL, 1, 0);
+       return _pv_read(cmd, cmd->mem, pv_name, NULL, 1, 0);
 }
index 08bff4a7e6d69f79e3fa54f96b5917b064853e97..7bc7eaf333af20f6fa57ef2294ba0f8d63dd62ad 100644 (file)
 //#define STRIPE_SIZE_MIN ( (unsigned) lvm_getpagesize() >> SECTOR_SHIFT)      /* PAGESIZE in sectors */
 //#define STRIPE_SIZE_MAX ( 512L * 1024L >> SECTOR_SHIFT)      /* 512 KB in sectors */
 //#define STRIPE_SIZE_LIMIT ((UINT_MAX >> 2) + 1)
-//#define PV_MIN_SIZE ( 512L * 1024L >> SECTOR_SHIFT)  /* 512 KB in sectors */
 //#define MAX_RESTRICTED_LVS 255       /* Used by FMT_RESTRICTED_LVIDS */
 #define MIRROR_LOG_OFFSET      2       /* sectors */
 #define VG_MEMPOOL_CHUNK       10240   /* in bytes, hint only */
+#define PV_PE_START_CALC       ((uint64_t) -1) /* Calculate pe_start value */
 
 /*
  * Ceiling(n / sz)
 
 
 /* Various flags */
+/* See metadata-exported.h for the complete list. */
 /* Note that the bits no longer necessarily correspond to LVM1 disk format */
 
-//#define PARTIAL_VG           0x00000001U     /* VG */
-//#define EXPORTED_VG                  0x00000002U     /* VG PV */
-//#define RESIZEABLE_VG                0x00000004U     /* VG */
-
 /* May any free extents on this PV be used or must they be left free? */
-//#define ALLOCATABLE_PV               0x00000008U     /* PV */
-
-#define SPINDOWN_LV            0x00000010U     /* LV */
-#define BADBLOCK_ON            0x00000020U     /* LV */
-//#define VISIBLE_LV           0x00000040U     /* LV */
-//#define FIXED_MINOR          0x00000080U     /* LV */
-/* FIXME Remove when metadata restructuring is completed */
-//#define SNAPSHOT             0x00001000U     /* LV - internal use only */
-//#define PVMOVE                       0x00002000U     /* VG LV SEG */
-//#define LOCKED                       0x00004000U     /* LV */
-//#define MIRRORED             0x00008000U     /* LV - internal use only */
-#define VIRTUAL                        0x00010000U     /* LV - internal use only */
-//#define MIRROR_LOG           0x00020000U     /* LV */
-//#define MIRROR_IMAGE         0x00040000U     /* LV */
-//#define MIRROR_NOTSYNCED     0x00080000U     /* LV */
-#define ACTIVATE_EXCL          0x00100000U     /* LV - internal use only */
-#define PRECOMMITTED           0x00200000U     /* VG - internal use only */
-//#define CONVERTING           0x00400000U     /* LV */
-
-//#define MISSING_PV           0x00800000U     /* PV */
-#define INCONSISTENT_VG                0x00800000U     /* VG - internal use only */
-//#define PARTIAL_LV           0x01000000U     /* LV - derived flag, not
-//                                                written out in metadata*/
-
-#define POSTORDER_FLAG         0x02000000U /* Not real flags, reserved for  */
-#define POSTORDER_OPEN_FLAG    0x04000000U /* temporary use inside vg_read_internal. */
-#define VIRTUAL_ORIGIN         0x08000000U     /* LV - internal use only */
-
-//#define LVM_READ                     0x00000100U     /* LV VG */
-//#define LVM_WRITE                    0x00000200U     /* LV VG */
-//#define CLUSTERED            0x00000400U     /* VG */
-#define SHARED                 0x00000800U     /* VG */
+
+#define SPINDOWN_LV            UINT64_C(0x00000010)    /* LV */
+#define BADBLOCK_ON            UINT64_C(0x00000020)    /* LV */
+#define VIRTUAL                        UINT64_C(0x00010000)    /* LV - internal use only */
+#define PRECOMMITTED           UINT64_C(0x00200000)    /* VG - internal use only */
+#define POSTORDER_FLAG         UINT64_C(0x02000000) /* Not real flags, reserved for  */
+#define POSTORDER_OPEN_FLAG    UINT64_C(0x04000000) /* temporary use inside vg_read_internal. */
+#define VIRTUAL_ORIGIN         UINT64_C(0x08000000)    /* LV - internal use only */
+
+#define SHARED                 UINT64_C(0x00000800)    /* VG */
 
 /* Format features flags */
-//#define FMT_SEGMENTS         0x00000001U     /* Arbitrary segment params? */
-//#define FMT_MDAS             0x00000002U     /* Proper metadata areas? */
-//#define FMT_TAGS             0x00000004U     /* Tagging? */
-//#define FMT_UNLIMITED_VOLS   0x00000008U     /* Unlimited PVs/LVs? */
-//#define FMT_RESTRICTED_LVIDS 0x00000010U     /* LVID <= 255 */
-//#define FMT_ORPHAN_ALLOCATABLE       0x00000020U     /* Orphan PV allocatable? */
 #define FMT_PRECOMMIT          0x00000040U     /* Supports pre-commit? */
-//#define FMT_RESIZE_PV                0x00000080U     /* Supports pvresize? */
-//#define FMT_UNLIMITED_STRIPESIZE 0x00000100U /* Unlimited stripe size? */
 
+struct dm_config_tree;
 struct metadata_area;
+struct alloc_handle;
+struct lvmcache_info;
 
 /* Per-format per-metadata area operations */
 struct metadata_area_ops {
+       struct dm_list list;
        struct volume_group *(*vg_read) (struct format_instance * fi,
                                         const char *vg_name,
-                                        struct metadata_area * mda);
+                                        struct metadata_area * mda,
+                                        int single_device);
        struct volume_group *(*vg_read_precommit) (struct format_instance * fi,
                                         const char *vg_name,
                                         struct metadata_area * mda);
@@ -174,9 +146,15 @@ struct metadata_area_ops {
         */
        unsigned (*mda_locns_match)(struct metadata_area *mda1,
                                    struct metadata_area *mda2);
+
+       struct device *(*mda_get_device)(struct metadata_area *mda);
+       int (*mda_export_text)(struct metadata_area *mda, struct dm_config_tree *cft,
+                              struct dm_config_node *parent);
+       int (*mda_import_text)(struct lvmcache_info *info, const struct dm_config_node *cn);
 };
 
-#define MDA_IGNORED 0x00000001
+#define MDA_IGNORED      0x00000001
+#define MDA_INCONSISTENT 0x00000002
 
 struct metadata_area {
        struct dm_list list;
@@ -190,14 +168,47 @@ struct metadata_area *mda_copy(struct dm_pool *mem,
 unsigned mda_is_ignored(struct metadata_area *mda);
 void mda_set_ignored(struct metadata_area *mda, unsigned ignored);
 unsigned mda_locns_match(struct metadata_area *mda1, struct metadata_area *mda2);
-void fid_add_mda(struct format_instance *fid, struct metadata_area *mda);
-int fid_add_mdas(struct format_instance *fid, struct dm_list *mdas);
+struct device *mda_get_device(struct metadata_area *mda);
+
+struct format_instance_ctx {
+       uint32_t type;
+       union {
+               const char *pv_id;
+               struct {
+                       const char *vg_name;
+                       const char *vg_id;
+               } vg_ref;
+               void *private;
+       } context;
+};
+
+struct format_instance *alloc_fid(const struct format_type *fmt,
+                                 const struct format_instance_ctx *fic);
+
+/*
+ * Format instance must always be set using pv_set_fid or vg_set_fid
+ * (NULL value as well), never asign it directly! This is essential
+ * for proper reference counting for the format instance.
+ */
+void pv_set_fid(struct physical_volume *pv, struct format_instance *fid);
+void vg_set_fid(struct volume_group *vg, struct format_instance *fid);
+
+/* FIXME: Add generic interface for mda counts based on given key. */
+int fid_add_mda(struct format_instance *fid, struct metadata_area *mda,
+               const char *key, size_t key_len, const unsigned sub_key);
+int fid_add_mdas(struct format_instance *fid, struct dm_list *mdas,
+                const char *key, size_t key_len);
+int fid_remove_mda(struct format_instance *fid, struct metadata_area *mda,
+                  const char *key, size_t key_len, const unsigned sub_key);
+struct metadata_area *fid_get_mda_indexed(struct format_instance *fid,
+               const char *key, size_t key_len, const unsigned sub_key);
 int mdas_empty_or_ignored(struct dm_list *mdas);
 
 #define seg_pvseg(seg, s)      (seg)->areas[(s)].u.pv.pvseg
 #define seg_dev(seg, s)                (seg)->areas[(s)].u.pv.pvseg->pv->dev
 #define seg_pe(seg, s)         (seg)->areas[(s)].u.pv.pvseg->pe
 #define seg_le(seg, s)         (seg)->areas[(s)].u.lv.le
+#define seg_metale(seg, s)     (seg)->meta_areas[(s)].u.lv.le
 
 struct name_list {
        struct dm_list list;
@@ -233,28 +244,59 @@ struct format_handler {
         * Return PV with given path.
         */
        int (*pv_read) (const struct format_type * fmt, const char *pv_name,
-                       struct physical_volume * pv, struct dm_list *mdas,
-                       int scan_label_only);
+                       struct physical_volume * pv, int scan_label_only);
+
+       /*
+        * Initialise a new PV.
+        */
+       int (*pv_initialise) (const struct format_type * fmt,
+                             int64_t label_sector,
+                             uint64_t pe_start,
+                             uint32_t extent_count,
+                             uint32_t extent_size,
+                             unsigned long data_alignment,
+                             unsigned long data_alignment_offset,
+                             struct physical_volume * pv);
 
        /*
         * Tweak an already filled out a pv ready for importing into a
         * vg.  eg. pe_count is format specific.
         */
        int (*pv_setup) (const struct format_type * fmt,
-                        uint64_t pe_start, uint32_t extent_count,
-                        uint32_t extent_size, unsigned long data_alignment,
-                        unsigned long data_alignment_offset,
-                        int pvmetadatacopies, uint64_t pvmetadatasize,
-                        unsigned metadataignore, struct dm_list * mdas,
-                        struct physical_volume * pv, struct volume_group * vg);
+                        struct physical_volume * pv,
+                        struct volume_group * vg);
+
+       /*
+        * Add metadata area to a PV. Changes will take effect on pv_write.
+        */
+       int (*pv_add_metadata_area) (const struct format_type * fmt,
+                                    struct physical_volume * pv,
+                                    int pe_start_locked,
+                                    unsigned metadata_index,
+                                    uint64_t metadata_size,
+                                    unsigned metadata_ignored);
+
+       /*
+        * Remove metadata area from a PV. Changes will take effect on pv_write.
+        */
+       int (*pv_remove_metadata_area) (const struct format_type *fmt,
+                                       struct physical_volume *pv,
+                                       unsigned metadata_index);
+
+       /*
+        * Recalculate the PV size taking into account any existing metadata areas.
+        */
+       int (*pv_resize) (const struct format_type *fmt,
+                         struct physical_volume *pv,
+                         struct volume_group *vg,
+                         uint64_t size);
 
        /*
         * Write a PV structure to disk. Fails if the PV is in a VG ie
         * pv->vg_name must be a valid orphan VG name
         */
        int (*pv_write) (const struct format_type * fmt,
-                        struct physical_volume * pv, struct dm_list * mdas,
-                        int64_t label_sector);
+                        struct physical_volume * pv);
 
        /*
         * Tweak an already filled out a lv eg, check there
@@ -278,10 +320,8 @@ struct format_handler {
        /*
         * Create format instance with a particular metadata area
         */
-       struct format_instance *(*create_instance) (const struct format_type *
-                                                   fmt, const char *vgname,
-                                                   const char *vgid,
-                                                   void *context);
+       struct format_instance *(*create_instance) (const struct format_type *fmt,
+                                                   const struct format_instance_ctx *fic);
 
        /*
         * Destructor for format instance
@@ -338,6 +378,12 @@ struct pv_list *find_pv_in_pv_list(const struct dm_list *pl,
 /* Find LV segment containing given LE */
 struct lv_segment *find_seg_by_le(const struct logical_volume *lv, uint32_t le);
 
+/* Find pool LV segment given a thin pool data or metadata segment. */
+struct lv_segment *find_pool_seg(const struct lv_segment *seg);
+
+/* Find some unused device_id for thin pool LV segment. */
+uint32_t get_free_pool_device_id(struct lv_segment *thin_pool_seg);
+
 /*
  * Remove a dev_dir if present.
  */
@@ -377,6 +423,14 @@ int add_seg_to_segs_using_this_lv(struct logical_volume *lv, struct lv_segment *
 int remove_seg_from_segs_using_this_lv(struct logical_volume *lv, struct lv_segment *seg);
 struct lv_segment *get_only_segment_using_this_lv(struct logical_volume *lv);
 
+int for_each_sub_lv(struct cmd_context *cmd, struct logical_volume *lv,
+                    int (*fn)(struct cmd_context *cmd,
+                              struct logical_volume *lv, void *data),
+                    void *data);
+int move_lv_segments(struct logical_volume *lv_to,
+                    struct logical_volume *lv_from,
+                    uint64_t set_status, uint64_t reset_status);
+
 /*
  * Calculate readahead from underlying PV devices
  */
@@ -385,9 +439,12 @@ void lv_calculate_readahead(const struct logical_volume *lv, uint32_t *read_ahea
 /*
  * For internal metadata caching.
  */
-int export_vg_to_buffer(struct volume_group *vg, char **buf);
+size_t export_vg_to_buffer(struct volume_group *vg, char **buf);
+int export_vg_to_config_tree(struct volume_group *vg, struct dm_config_tree **cft);
 struct volume_group *import_vg_from_buffer(const char *buf,
                                           struct format_instance *fid);
+struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft,
+                                               struct format_instance *fid);
 
 /*
  * Mirroring functions
@@ -398,6 +455,25 @@ struct volume_group *import_vg_from_buffer(const char *buf,
  */
 int fixup_imported_mirrors(struct volume_group *vg);
 
+/*
+ * From thin_manip.c
+ */
+int attach_pool_metadata_lv(struct lv_segment *pool_seg,
+                           struct logical_volume *pool_metadata_lv);
+int attach_pool_data_lv(struct lv_segment *pool_seg,
+                       struct logical_volume *pool_data_lv);
+int attach_pool_lv(struct lv_segment *seg, struct logical_volume *pool_lv,
+                  struct logical_volume *origin_lv);
+int detach_pool_lv(struct lv_segment *seg);
+int attach_pool_message(struct lv_segment *pool_seg, dm_thin_message_t type,
+                       struct logical_volume *lv, uint32_t delete_id,
+                       int auto_increment);
+int pool_has_message(const struct lv_segment *seg,
+                    const struct logical_volume *lv, uint32_t device_id);
+int pool_below_threshold(const struct lv_segment *pool_seg);
+int extend_pool(struct logical_volume *lv, const struct segment_type *segtype,
+               struct alloc_handle *ah, uint32_t stripes, uint32_t stripe_size);
+
 /*
  * Begin skeleton for external LVM library
  */
@@ -407,8 +483,8 @@ struct id pv_vgid(const struct physical_volume *pv);
 
 struct physical_volume *pv_by_path(struct cmd_context *cmd, const char *pv_name);
 int add_pv_to_vg(struct volume_group *vg, const char *pv_name,
-                struct physical_volume *pv);
-int vg_mark_partial_lvs(struct volume_group *vg);
+                struct physical_volume *pv, struct pvcreate_params *pp);
+
 int is_mirror_image_removable(struct logical_volume *mimage_lv, void *baton);
 
 uint64_t find_min_mda_size(struct dm_list *mdas);
index 1be07cfd106d426e474d1b4f535e11968095f340..c4683dff6e1cee07da9e37aaad5571a9ae0a74fd 100644 (file)
@@ -24,7 +24,6 @@
 #include "lvm-string.h"
 #include "str_list.h"
 #include "locking.h"   /* FIXME Should not be used in this file */
-#include "memlock.h"
 
 #include "defaults.h" /* FIXME: should this be defaults.h? */
 
@@ -72,14 +71,6 @@ struct logical_volume *find_temporary_mirror(const struct logical_volume *lv)
        return NULL;
 }
 
-int lv_is_mirrored(const struct logical_volume *lv)
-{
-       if (lv->status & MIRRORED)
-               return 1;
-
-       return 0;
-}
-
 /*
  * cluster_mirror_is_available
  *
@@ -89,7 +80,7 @@ int lv_is_mirrored(const struct logical_volume *lv)
  *
  * Returns: 1 if available, 0 otherwise
  */
-static int cluster_mirror_is_available(struct logical_volume *lv)
+static int _cluster_mirror_is_available(struct logical_volume *lv)
 {
        unsigned attr = 0;
        struct cmd_context *cmd = lv->vg->cmd;
@@ -122,16 +113,26 @@ uint32_t lv_mirror_count(const struct logical_volume *lv)
                return 1;
 
        seg = first_seg(lv);
-       mirrors = seg->area_count;
+
+       /* FIXME: RAID10 only supports 2 copies right now */
+       if (!strcmp(seg->segtype->name, "raid10"))
+               return 2;
+
+       if (lv->status & PVMOVE)
+               return seg->area_count;
+
+       mirrors = 0;
 
        for (s = 0; s < seg->area_count; s++) {
                if (seg_type(seg, s) != AREA_LV)
                        continue;
                if (is_temporary_mirror_layer(seg_lv(seg, s)))
-                       mirrors += lv_mirror_count(seg_lv(seg, s)) - 1;
+                       mirrors += lv_mirror_count(seg_lv(seg, s));
+               else
+                       mirrors++;
        }
 
-       return mirrors;
+       return mirrors ? mirrors : 1;
 }
 
 struct lv_segment *find_mirror_seg(struct lv_segment *seg)
@@ -167,8 +168,8 @@ uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
 
        if (region_max < UINT32_MAX && region_size > region_max) {
                region_size = (uint32_t) region_max;
-               log_print("Using reduced mirror region size of %" PRIu32
-                         " sectors", region_size);
+               log_print_unless_silent("Using reduced mirror region size of %" PRIu32
+                                       " sectors", region_size);
        }
 
        return region_size;
@@ -200,7 +201,7 @@ uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
  */
 int shift_mirror_images(struct lv_segment *mirrored_seg, unsigned mimage)
 {
-       int i;
+       unsigned i;
        struct lv_segment_area area;
 
        if (mimage >= mirrored_seg->area_count) {
@@ -285,6 +286,11 @@ static int _init_mirror_log(struct cmd_context *cmd,
        uint64_t orig_status = log_lv->status;
        int was_active = 0;
 
+       if (test_mode()) {
+               log_verbose("Test mode: Skipping mirror log initialisation.");
+               return 1;
+       }
+
        if (!activation() && in_sync) {
                log_error("Aborting. Unable to create in-sync mirror log "
                          "while activation is disabled.");
@@ -322,6 +328,9 @@ static int _init_mirror_log(struct cmd_context *cmd,
 
        backup(log_lv->vg);
 
+       /* Wait for events following any deactivation before reactivating */
+       sync_local_dev_names(cmd);
+
        if (!activate_lv(cmd, log_lv)) {
                log_error("Aborting. Failed to activate mirror log.");
                goto revert_new_lv;
@@ -329,9 +338,7 @@ static int _init_mirror_log(struct cmd_context *cmd,
 
        /* Remove the temporary tags */
        dm_list_iterate_items(sl, tags)
-               if (!str_list_del(&log_lv->tags, sl->str))
-                       log_error("Failed to remove tag %s from mirror log.",
-                                 sl->str);
+               str_list_del(&log_lv->tags, sl->str);
 
        if (activation() && !set_lv(cmd, log_lv, log_lv->size,
                                    in_sync ? -1 : 0)) {
@@ -368,9 +375,7 @@ revert_new_lv:
        log_lv->status = orig_status;
 
        dm_list_iterate_items(sl, tags)
-               if (!str_list_del(&log_lv->tags, sl->str))
-                       log_error("Failed to remove tag %s from mirror log.",
-                                 sl->str);
+               str_list_del(&log_lv->tags, sl->str);
 
        if (remove_on_failure && !lv_remove(log_lv)) {
                log_error("Manual intervention may be required to remove "
@@ -391,6 +396,22 @@ activate_lv:
        return 0;
 }
 
+/*
+ * Activate an LV similarly (i.e. SH or EX) to a given "model" LV
+ */
+static int _activate_lv_like_model(struct logical_volume *model,
+                                  struct logical_volume *lv)
+{
+       if (lv_is_active_exclusive(model)) {
+               if (!activate_lv_excl(lv->vg->cmd, lv))
+                       return_0;
+       } else {
+               if (!activate_lv(lv->vg->cmd, lv))
+                       return_0;
+       }
+       return 1;
+}
+
 /*
  * Delete independent/orphan LV, it must acquire lock.
  */
@@ -414,9 +435,13 @@ static int _delete_lv(struct logical_volume *mirror_lv, struct logical_volume *l
                }
        }
 
-       if (!activate_lv(cmd, lv))
+       // FIXME: shouldn't the activation type be based on mirror_lv, not lv?
+       if (!_activate_lv_like_model(lv, lv))
                return_0;
 
+       /* FIXME Is this superfluous now? */
+       sync_local_dev_names(cmd);
+
        if (!deactivate_lv(cmd, lv))
                return_0;
 
@@ -551,8 +576,14 @@ static int _mirrored_lv_in_sync(struct logical_volume *lv)
 
        if (!lv_mirror_percent(lv->vg->cmd, lv, 0, &sync_percent,
                               NULL)) {
-               log_error("Unable to determine mirror sync status of %s/%s.",
-                         lv->vg->name, lv->name);
+               if (lv_is_active_but_not_locally(lv))
+                       log_error("Unable to determine mirror sync status of"
+                                 " remotely active LV, %s/%s",
+                                 lv->vg->name, lv->name);
+               else
+                       log_error("Unable to determine mirror "
+                                 "sync status of %s/%s.",
+                                 lv->vg->name, lv->name);
                return 0;
        }
 
@@ -576,6 +607,7 @@ static int _split_mirror_images(struct logical_volume *lv,
        struct lv_segment *mirrored_seg = first_seg(lv);
        struct dm_list split_images;
        struct lv_list *lvl;
+       struct cmd_context *cmd = lv->vg->cmd;
 
        if (!(lv->status & MIRRORED)) {
                log_error("Unable to split non-mirrored LV, %s",
@@ -584,7 +616,7 @@ static int _split_mirror_images(struct logical_volume *lv,
        }
 
        if (!split_count) {
-               log_error("split_count is zero!");
+               log_error(INTERNAL_ERROR "split_count is zero!");
                return 0;
        }
 
@@ -604,43 +636,55 @@ static int _split_mirror_images(struct logical_volume *lv,
                return 0;
        }
 
+       /*
+        * Step 1:
+        *   Remove the images from the mirror.
+        *   Make them visible, independent LVs (don't change names yet).
+        *   Track them in a list for later instantiation.
+        */
        dm_list_init(&split_images);
        for (i = 0; i < split_count; i++) {
                mirrored_seg->area_count--;
                sub_lv = seg_lv(mirrored_seg, mirrored_seg->area_count);
 
                sub_lv->status &= ~MIRROR_IMAGE;
-               lv_set_visible(sub_lv);
-               release_lv_segment_area(mirrored_seg, mirrored_seg->area_count,
-                                       mirrored_seg->area_len);
+               if (!release_lv_segment_area(mirrored_seg, mirrored_seg->area_count, mirrored_seg->area_len))
+                       return_0;
 
                log_very_verbose("%s assigned to be split", sub_lv->name);
 
                if (!new_lv) {
+                       lv_set_visible(sub_lv);
                        new_lv = sub_lv;
-                       new_lv->name = dm_pool_strdup(lv->vg->cmd->mem,
-                                                     split_name);
-                       if (!new_lv->name) {
-                               log_error("Unable to rename newly split LV");
-                               return 0;
-                       }
-               } else {
-                       lvl = dm_pool_alloc(lv->vg->cmd->mem, sizeof(*lvl));
-                       if (!lvl) {
-                               log_error("lv_list alloc failed");
-                               return 0;
-                       }
-                       lvl->lv = sub_lv;
-                       dm_list_add(&split_images, &lvl->list);
+                       continue;
                }
+
+               /* If there is more than one image being split, add to list */
+               lvl = dm_pool_alloc(lv->vg->vgmem, sizeof(*lvl));
+               if (!lvl) {
+                       log_error("lv_list alloc failed");
+                       return 0;
+               }
+               lvl->lv = sub_lv;
+               dm_list_add(&split_images, &lvl->list);
+       }
+
+       new_lv->name = dm_pool_strdup(lv->vg->vgmem, split_name);
+       if (!new_lv->name) {
+               log_error("Unable to rename newly split LV");
+               return 0;
        }
 
        if (!dm_list_empty(&split_images)) {
                size_t len = strlen(new_lv->name) + 32;
                char *layer_name, format[len];
 
-               if (!insert_layer_for_lv(lv->vg->cmd, new_lv,
-                                        0, "_mimage_%d")) {
+               /*
+                * A number of images have been split and
+                * a new mirror layer must be formed
+                */
+
+               if (!insert_layer_for_lv(cmd, new_lv, 0, "_mimage_%d")) {
                        log_error("Failed to build new mirror, %s",
                                  new_lv->name);
                        return 0;
@@ -651,10 +695,12 @@ static int _split_mirror_images(struct logical_volume *lv,
                dm_list_iterate_items(lvl, &split_images) {
                        sub_lv = lvl->lv;
 
-                       dm_snprintf(format, len, "%s_mimage_%%d",
-                                   new_lv->name);
-
-                       layer_name = dm_pool_alloc(lv->vg->cmd->mem, len);
+                       if (dm_snprintf(format, len, "%s_mimage_%%d",
+                                       new_lv->name) < 0) {
+                               log_error("Failed to build new image name.");
+                               return 0;
+                       }
+                       layer_name = dm_pool_alloc(lv->vg->vgmem, len);
                        if (!layer_name) {
                                log_error("Unable to allocate memory");
                                return 0;
@@ -696,7 +742,7 @@ static int _split_mirror_images(struct logical_volume *lv,
                if (!remove_layer_from_lv(lv, sub_lv))
                        return_0;
                lv->status &= ~MIRRORED;
-               lv->status &= ~MIRROR_NOTSYNCED;
+               lv->status &= ~LV_NOTSYNCED;
        }
 
        if (!vg_write(mirrored_seg->lv->vg)) {
@@ -705,42 +751,54 @@ static int _split_mirror_images(struct logical_volume *lv,
        }
 
        /*
-        * Suspend the original device and all its sub devices
+        * Suspend the mirror - this includes all the sub-LVs and
+        *                      soon-to-be-split sub-LVs
         */
-       if (!suspend_lv(mirrored_seg->lv->vg->cmd, mirrored_seg->lv)) {
+       if (!suspend_lv(cmd, mirrored_seg->lv)) {
                log_error("Failed to lock %s", mirrored_seg->lv->name);
                vg_revert(mirrored_seg->lv->vg);
                return 0;
        }
 
        if (!vg_commit(mirrored_seg->lv->vg)) {
-               resume_lv(mirrored_seg->lv->vg->cmd, mirrored_seg->lv);
+               resume_lv(cmd, mirrored_seg->lv);
                return 0;
        }
 
-       /* Bring newly split-off LV into existence */
-       if (!activate_lv(lv->vg->cmd, new_lv)) {
-               log_error("Failed to activate newly split LV, %s",
-                         new_lv->name);
+       log_very_verbose("Updating \"%s\" in kernel", mirrored_seg->lv->name);
+
+       /*
+        * Resume the mirror - this also activates the visible, independent
+        *                     soon-to-be-split sub-LVs
+        */
+       if (!resume_lv(cmd, mirrored_seg->lv)) {
+               log_error("Problem resuming %s", mirrored_seg->lv->name);
                return 0;
        }
 
-       /* Resume altered original LV */
-       log_very_verbose("Updating \"%s\" in kernel", mirrored_seg->lv->name);
-       if (!resume_lv(mirrored_seg->lv->vg->cmd, mirrored_seg->lv)) {
-               log_error("Problem reactivating %s", mirrored_seg->lv->name);
+       /*
+        * Recycle newly split LV so it is properly renamed.
+        *   Cluster requires the extra deactivate/activate calls.
+        */
+       if (vg_is_clustered(lv->vg) &&
+           (!deactivate_lv(cmd, new_lv) ||
+            !_activate_lv_like_model(lv, new_lv))) {
+               log_error("Failed to rename newly split LV in the kernel");
+               return 0;
+       }
+       if (!suspend_lv(cmd, new_lv) || !resume_lv(cmd, new_lv)) {
+               log_error("Failed to rename newly split LV in the kernel");
                return 0;
        }
 
+       /* Remove original mirror layer if it has been converted to linear */
        if (sub_lv && !_delete_lv(lv, sub_lv))
                return_0;
 
+       /* Remove the log if it has been converted to linear */
        if (detached_log_lv && !_delete_lv(lv, detached_log_lv))
                return_0;
 
-       log_very_verbose("%" PRIu32 " image(s) detached from %s",
-                        split_count, lv->name);
-
        return 1;
 }
 
@@ -774,7 +832,7 @@ static int _remove_mirror_images(struct logical_volume *lv,
                                 int (*is_removable)(struct logical_volume *, void *),
                                 void *removable_baton,
                                 unsigned remove_log, unsigned collapse,
-                                uint32_t *removed)
+                                uint32_t *removed, int preferred_only)
 {
        uint32_t m;
        int32_t s;
@@ -786,12 +844,13 @@ static int _remove_mirror_images(struct logical_volume *lv,
        uint32_t new_area_count = mirrored_seg->area_count;
        struct lv_list *lvl;
        struct dm_list tmp_orphan_lvs;
+       int orig_removed = num_removed;
 
        if (removed)
                *removed = 0;
 
-       log_very_verbose("Reducing mirror set from %" PRIu32 " to %"
-                        PRIu32 " image(s)%s.",
+       log_very_verbose("Reducing mirror set %s from %" PRIu32 " to %"
+                        PRIu32 " image(s)%s.", lv->name,
                         old_area_count, old_area_count - num_removed,
                         remove_log ? " and no log volume" : "");
 
@@ -800,12 +859,14 @@ static int _remove_mirror_images(struct logical_volume *lv,
                return 0;
        }
 
+       num_removed = 0;
+
        /* Move removable_pvs to end of array */
        for (s = mirrored_seg->area_count - 1;
-            s >= 0 && old_area_count - new_area_count < num_removed;
+            s >= 0 && old_area_count - new_area_count < orig_removed;
             s--) {
                sub_lv = seg_lv(mirrored_seg, s);
-               if (!is_temporary_mirror_layer(sub_lv) &&
+               if (!(is_temporary_mirror_layer(sub_lv) && lv_mirror_count(sub_lv) != 1) &&
                    is_removable(sub_lv, removable_baton)) {
                        /*
                         * Check if the user is trying to pull the
@@ -815,14 +876,18 @@ static int _remove_mirror_images(struct logical_volume *lv,
                        if ((s == 0) && !_mirrored_lv_in_sync(lv) &&
                            !(lv->status & PARTIAL_LV)) {
                                log_error("Unable to remove primary mirror image while mirror is not in-sync");
-                               return_0;
+                               return 0;
                        }
                        if (!shift_mirror_images(mirrored_seg, s))
                                return_0;
-                       new_area_count--;
+                       --new_area_count;
+                       ++num_removed;
                }
        }
 
+       if (!preferred_only)
+               num_removed = orig_removed;
+
        /*
         * If removable_pvs were specified, then they have been shifted
         * to the end to ensure they are removed.  The remaining balance
@@ -844,7 +909,8 @@ static int _remove_mirror_images(struct logical_volume *lv,
                }
                lvl->lv = seg_lv(mirrored_seg, m);
                dm_list_add(&tmp_orphan_lvs, &lvl->list);
-               release_lv_segment_area(mirrored_seg, m, mirrored_seg->area_len);
+               if (!release_lv_segment_area(mirrored_seg, m, mirrored_seg->area_len))
+                       return_0;
        }
        mirrored_seg->area_count = new_area_count;
 
@@ -859,12 +925,19 @@ static int _remove_mirror_images(struct logical_volume *lv,
                detached_log_lv = detach_mirror_log(mirrored_seg);
                if (!remove_layer_from_lv(lv, temp_layer_lv))
                        return_0;
-               lv->status &= ~MIRRORED;
-               lv->status &= ~MIRROR_NOTSYNCED;
                if (collapse && !_merge_mirror_images(lv, &tmp_orphan_lvs)) {
                        log_error("Failed to add mirror images");
                        return 0;
                }
+                /*
+                 * No longer a mirror? Even though new_area_count was 1,
+                 * _merge_mirror_images may have resulted into lv being still a
+                 * mirror. Fix up the flags if we only have one image left.
+                 */
+                if (lv_mirror_count(lv) == 1) {
+                    lv->status &= ~MIRRORED;
+                    lv->status &= ~LV_NOTSYNCED;
+                }
                mirrored_seg = first_seg(lv);
                if (remove_log && !detached_log_lv)
                        detached_log_lv = detach_mirror_log(mirrored_seg);
@@ -875,7 +948,7 @@ static int _remove_mirror_images(struct logical_volume *lv,
                 * It can happen for vgreduce --removemissing. */
                detached_log_lv = detach_mirror_log(mirrored_seg);
                lv->status &= ~MIRRORED;
-               lv->status &= ~MIRROR_NOTSYNCED;
+               lv->status &= ~LV_NOTSYNCED;
                if (!replace_lv_with_error_segment(lv))
                        return_0;
        } else if (remove_log)
@@ -946,7 +1019,7 @@ static int _remove_mirror_images(struct logical_volume *lv,
                if (!resume_lv(detached_log_lv->vg->cmd, detached_log_lv)) {
                        log_error("Failed to resume %s",
                                  detached_log_lv->name);
-                       return_0;
+                       return 0;
                }
        }
 
@@ -968,11 +1041,11 @@ static int _remove_mirror_images(struct logical_volume *lv,
        }
 
        /* FIXME: second suspend should not be needed
-        * Explicitly suspend temporary LV
-        * This balance memlock_inc() calls with memlock_dec() in resume
-        * (both localy and in cluster) and also properly propagates precommited
+        * Explicitly suspend temporary LV.
+        * This balances critical_section_inc() calls with critical_section_dec()
+        * in resume (both local and cluster) and also properly propagates precommitted
         * metadata into dm table on other nodes.
-        * (visible flag set causes the suspend is not properly propagated?)
+        * FIXME: check propagation of suspend with visible flag
         */
        if (temp_layer_lv && !suspend_lv(temp_layer_lv->vg->cmd, temp_layer_lv))
                log_error("Problem suspending temporary LV %s", temp_layer_lv->name);
@@ -1022,7 +1095,7 @@ static int _remove_mirror_images(struct logical_volume *lv,
                        /* As a result, unnecessary sync may run after
                         * collapsing. But safe.*/
                        log_error("Failed to initialize log device");
-                       return_0;
+                       return 0;
                }
        }
 
@@ -1030,7 +1103,7 @@ static int _remove_mirror_images(struct logical_volume *lv,
                *removed = old_area_count - new_area_count;
 
        log_very_verbose("%" PRIu32 " image(s) removed from %s",
-                        old_area_count - num_removed, lv->name);
+                        old_area_count - new_area_count, lv->name);
 
        return 1;
 }
@@ -1046,6 +1119,9 @@ int remove_mirror_images(struct logical_volume *lv, uint32_t num_mirrors,
        uint32_t existing_mirrors = lv_mirror_count(lv);
        struct logical_volume *next_lv = lv;
 
+       int preferred_only = 1;
+       int retries = 0;
+
        num_removed = existing_mirrors - num_mirrors;
 
        /* num_removed can be 0 if the function is called just to remove log */
@@ -1057,17 +1133,33 @@ int remove_mirror_images(struct logical_volume *lv, uint32_t num_mirrors,
 
                if (!_remove_mirror_images(next_lv, removed_once,
                                           is_removable, removable_baton,
-                                          remove_log, 0, &r))
+                                          remove_log, 0, &r, preferred_only))
                        return_0;
 
-               if (r < removed_once) {
+               if (r < removed_once || !removed_once) {
                        /* Some mirrors are removed from the temporary mirror,
                         * but the temporary layer still exists.
                         * Down the stack and retry for remainder. */
                        next_lv = find_temporary_mirror(next_lv);
+                       if (!next_lv) {
+                               preferred_only = 0;
+                               next_lv = lv;
+                       }
                }
 
                num_removed -= r;
+
+               /*
+                * if there are still images to be removed, try again; this is
+                * required since some temporary layers may have been reduced
+                * to 1, at which point they are made removable, just like
+                * normal images
+                */
+               if (!next_lv && !preferred_only && !retries && num_removed) {
+                       ++retries;
+                       preferred_only = 1;
+               }
+
        } while (next_lv && num_removed);
 
        if (num_removed) {
@@ -1121,7 +1213,7 @@ int collapse_mirrored_lv(struct logical_volume *lv)
 
                if (!_remove_mirror_images(mirror_seg->lv,
                                           mirror_seg->area_count - 1,
-                                          _no_removable_images, NULL, 0, 1, NULL)) {
+                                          _no_removable_images, NULL, 0, 1, NULL, 0)) {
                        log_error("Failed to release mirror images");
                        return 0;
                }
@@ -1130,19 +1222,21 @@ int collapse_mirrored_lv(struct logical_volume *lv)
        return 1;
 }
 
-static int get_mirror_fault_policy(struct cmd_context *cmd __attribute__((unused)),
+#if 0
+/* FIXME: reconfigure_mirror_images: remove this code? */
+static int _get_mirror_fault_policy(struct cmd_context *cmd __attribute__((unused)),
                                   int log_policy)
 {
        const char *policy;
 
        if (log_policy)
-               policy = find_config_str(NULL, "activation/mirror_log_fault_policy",
+               policy = dm_config_find_str(NULL, "activation/mirror_log_fault_policy",
                                         DEFAULT_MIRROR_LOG_FAULT_POLICY);
        else {
-               policy = find_config_str(NULL, "activation/mirror_image_fault_policy",
+               policy = dm_config_find_str(NULL, "activation/mirror_image_fault_policy",
                                         NULL);
                if (!policy)
-                       policy = find_config_str(NULL, "activation/mirror_device_fault_policy",
+                       policy = dm_config_find_str(NULL, "activation/mirror_device_fault_policy",
                                                 DEFAULT_MIRROR_IMAGE_FAULT_POLICY);
        }
 
@@ -1161,14 +1255,14 @@ static int get_mirror_fault_policy(struct cmd_context *cmd __attribute__((unused
        return MIRROR_REMOVE;
 }
 
-static int get_mirror_log_fault_policy(struct cmd_context *cmd)
+static int _get_mirror_log_fault_policy(struct cmd_context *cmd)
 {
-       return get_mirror_fault_policy(cmd, 1);
+       return _get_mirror_fault_policy(cmd, 1);
 }
 
-static int get_mirror_device_fault_policy(struct cmd_context *cmd)
+static int _get_mirror_device_fault_policy(struct cmd_context *cmd)
 {
-       return get_mirror_fault_policy(cmd, 0);
+       return _get_mirror_fault_policy(cmd, 0);
 }
 
 /*
@@ -1184,7 +1278,7 @@ static int get_mirror_device_fault_policy(struct cmd_context *cmd)
  *
  * Returns: 0 on failure, 1 on reconfig, -1 if no reconfig done
  */
-static int replace_mirror_images(struct lv_segment *mirrored_seg,
+static int _replace_mirror_images(struct lv_segment *mirrored_seg,
                                 uint32_t num_mirrors,
                                 int log_policy, int in_sync)
 {
@@ -1247,7 +1341,7 @@ int reconfigure_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirr
 
        r = _remove_mirror_images(mirrored_seg->lv, old_num_mirrors - num_mirrors,
                                  is_mirror_image_removable, removable_pvs,
-                                 remove_log, 0, NULL);
+                                 remove_log, 0, NULL, 0);
        if (!r)
                /* Unable to remove bad devices */
                return 0;
@@ -1255,10 +1349,10 @@ int reconfigure_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirr
        log_warn("WARNING: Bad device removed from mirror volume, %s/%s",
                  mirrored_seg->lv->vg->name, mirrored_seg->lv->name);
 
-       log_policy = get_mirror_log_fault_policy(mirrored_seg->lv->vg->cmd);
-       dev_policy = get_mirror_device_fault_policy(mirrored_seg->lv->vg->cmd);
+       log_policy = _get_mirror_log_fault_policy(mirrored_seg->lv->vg->cmd);
+       dev_policy = _get_mirror_device_fault_policy(mirrored_seg->lv->vg->cmd);
 
-       r = replace_mirror_images(mirrored_seg,
+       r = _replace_mirror_images(mirrored_seg,
                                  (dev_policy != MIRROR_REMOVE) ?
                                  old_num_mirrors : num_mirrors,
                                  log_policy, in_sync);
@@ -1286,6 +1380,7 @@ int reconfigure_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirr
         */
        return 1;
 }
+#endif
 
 static int _create_mimage_lvs(struct alloc_handle *ah,
                              uint32_t num_mirrors,
@@ -1295,7 +1390,7 @@ static int _create_mimage_lvs(struct alloc_handle *ah,
                              struct logical_volume **img_lvs,
                              int log)
 {
-       uint32_t m;
+       uint32_t m, first_area;
        char *img_name;
        size_t len;
        
@@ -1322,9 +1417,11 @@ static int _create_mimage_lvs(struct alloc_handle *ah,
                }
 
                if (log) {
-                       if (!lv_add_log_segment(ah, m * stripes + 1, img_lvs[m], 0)) {
-                               log_error("Aborting. Failed to add mirror image segment "
-                                         "to %s. Remove new LV and retry.",
+                       first_area = m * stripes + (log - 1);
+
+                       if (!lv_add_log_segment(ah, first_area, img_lvs[m], 0)) {
+                               log_error("Failed to add mirror image segment"
+                                         " to %s. Remove new LV and retry.",
                                          img_lvs[m]->name);
                                return 0;
                        }
@@ -1378,7 +1475,8 @@ int remove_mirrors_from_segments(struct logical_volume *lv,
                }
 
                for (s = new_mirrors + 1; s < seg->area_count; s++)
-                       release_lv_segment_area(seg, s, seg->area_len);
+                       if (!release_and_discard_lv_segment_area(seg, s, seg->area_len))
+                               return_0;
 
                seg->area_count = new_mirrors + 1;
 
@@ -1405,7 +1503,10 @@ const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr)
        return NULL;
 }
 
-const char *get_pvmove_pvname_from_lv(struct logical_volume *lv)
+/*
+ * Find first pvmove LV referenced by a segment of an LV.
+ */
+struct logical_volume *find_pvmove_lv_in_lv(struct logical_volume *lv)
 {
        struct lv_segment *seg;
        uint32_t s;
@@ -1414,16 +1515,29 @@ const char *get_pvmove_pvname_from_lv(struct logical_volume *lv)
                for (s = 0; s < seg->area_count; s++) {
                        if (seg_type(seg, s) != AREA_LV)
                                continue;
-                       return get_pvmove_pvname_from_lv_mirr(seg_lv(seg, s));
+                       if (seg_lv(seg, s)->status & PVMOVE)
+                               return seg_lv(seg, s);
                }
        }
 
        return NULL;
 }
 
+const char *get_pvmove_pvname_from_lv(struct logical_volume *lv)
+{
+       struct logical_volume *pvmove_lv;
+
+       pvmove_lv = find_pvmove_lv_in_lv(lv);
+
+       if (pvmove_lv)
+               return get_pvmove_pvname_from_lv_mirr(pvmove_lv);
+       else
+               return NULL;
+}
+
 struct logical_volume *find_pvmove_lv(struct volume_group *vg,
                                      struct device *dev,
-                                     uint32_t lv_type)
+                                     uint64_t lv_type)
 {
        struct lv_list *lvl;
        struct logical_volume *lv;
@@ -1453,14 +1567,18 @@ struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd,
                                                  struct volume_group *vg,
                                                  const char *name,
                                                  const char *uuid __attribute__((unused)),
-                                                 uint32_t lv_type)
+                                                 uint64_t lv_type)
 {
        struct physical_volume *pv;
+       struct logical_volume *lv;
 
        if (!(pv = find_pv_by_name(cmd, name)))
                return_NULL;
 
-       return find_pvmove_lv(vg, pv->dev, lv_type);
+       lv = find_pvmove_lv(vg, pv->dev, lv_type);
+       free_pv_fid(pv);
+
+       return lv;
 }
 
 struct dm_list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
@@ -1507,7 +1625,7 @@ struct dm_list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
        return lvs;
 }
 
-percent_t copy_percent(struct logical_volume *lv_mirr)
+percent_t copy_percent(const struct logical_volume *lv_mirr)
 {
        uint32_t numerator = 0u, denominator = 0u;
        struct lv_segment *seg;
@@ -1559,7 +1677,7 @@ int add_mirrors_to_segments(struct cmd_context *cmd, struct logical_volume *lv,
        uint32_t adjusted_region_size;
        int r = 1;
 
-       if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv, 1)))
+       if (!(parallel_areas = build_parallel_areas_from_lv(lv, 1)))
                return_0;
 
        if (!(segtype = get_segtype_from_string(cmd, "mirror")))
@@ -1627,7 +1745,7 @@ int remove_mirror_log(struct cmd_context *cmd,
                init_mirror_in_sync(1);
        else {
                /* A full resync will take place */
-               lv->status &= ~MIRROR_NOTSYNCED;
+               lv->status &= ~LV_NOTSYNCED;
                init_mirror_in_sync(0);
        }
 
@@ -1720,8 +1838,8 @@ static struct logical_volume *_set_up_mirror_log(struct cmd_context *cmd,
                                                 int in_sync)
 {
        struct logical_volume *log_lv;
-       const char *suffix, *c;
-       char *lv_name;
+       const char *suffix, *lv_name;
+       char *tmp_name;
        size_t len;
        struct lv_segment *seg;
 
@@ -1740,27 +1858,24 @@ static struct logical_volume *_set_up_mirror_log(struct cmd_context *cmd,
            strstr(seg_lv(seg, 0)->name, MIRROR_SYNC_LAYER)) {
                lv_name = lv->name;
                suffix = "_mlogtmp_%d";
-       } else if ((c = strstr(lv->name, MIRROR_SYNC_LAYER))) {
-               len = c - lv->name + 1;
-               if (!(lv_name = alloca(len)) ||
-                   !dm_snprintf(lv_name, len, "%s", lv->name)) {
-                       log_error("mirror log name allocation failed");
-                       return 0;
-               }
+       } else if ((lv_name = strstr(lv->name, MIRROR_SYNC_LAYER))) {
+               len = lv_name - lv->name;
+               tmp_name = alloca(len + 1);
+               tmp_name[len] = '\0';
+               lv_name = strncpy(tmp_name, lv->name, len);
                suffix = "_mlog";
        } else {
                lv_name = lv->name;
                suffix = "_mlog";
        }
 
-       if (!(log_lv = _create_mirror_log(lv, ah, alloc,
-                                         (const char *) lv_name, suffix))) {
+       if (!(log_lv = _create_mirror_log(lv, ah, alloc, lv_name, suffix))) {
                log_error("Failed to create mirror log.");
                return NULL;
        }
 
        if ((log_count > 1) &&
-           !_form_mirror(cmd, ah, log_lv, log_count-1, 1, 0, region_size, 1)) {
+           !_form_mirror(cmd, ah, log_lv, log_count-1, 1, 0, region_size, 2)) {
                log_error("Failed to form mirrored log.");
                return NULL;
        }
@@ -1791,27 +1906,35 @@ int add_mirror_log(struct cmd_context *cmd, struct logical_volume *lv,
        percent_t sync_percent;
        int in_sync;
        struct logical_volume *log_lv;
-       struct lvinfo info;
+       unsigned old_log_count;
        int r = 0;
 
+       if (vg_is_clustered(lv->vg) && (log_count > 1)) {
+               log_error("Log type, \"mirrored\", is unavailable to cluster mirrors");
+               return 0;
+       }
+
        if (dm_list_size(&lv->segments) != 1) {
                log_error("Multiple-segment mirror is not supported");
                return 0;
        }
 
-       /*
-        * We are unable to convert the log of inactive cluster mirrors
-        * due to the inability to detect whether the mirror is active
-        * on remote nodes (even though it is inactive on this node)
-        */
-       if (vg_is_clustered(lv->vg) &&
-           !(lv_info(cmd, lv, 0, &info, 0, 0) && info.exists)) {
-               log_error("Unable to convert the log of inactive "
-                         "cluster mirror %s", lv->name);
+       if (lv_is_active_but_not_locally(lv)) {
+               log_error("Unable to convert the log of a mirror, %s, that is "
+                         "active remotely but not locally", lv->name);
                return 0;
        }
 
-       if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv, 0)))
+       log_lv = first_seg(lv)->log_lv;
+       old_log_count = (log_lv) ? lv_mirror_count(log_lv) : 0;
+       if (old_log_count == log_count) {
+               log_verbose("Mirror already has a %s log",
+                           !log_count ? "core" :
+                           (log_count == 1) ? "disk" : "mirrored");
+               return 1;
+       }
+
+       if (!(parallel_areas = build_parallel_areas_from_lv(lv, 0)))
                return_0;
 
        if (!(segtype = get_segtype_from_string(cmd, "mirror")))
@@ -1826,16 +1949,29 @@ int add_mirror_log(struct cmd_context *cmd, struct logical_volume *lv,
 
        /* allocate destination extents */
        ah = allocate_extents(lv->vg, NULL, segtype,
-                             0, 0, log_count, region_size, 0,
-                             allocatable_pvs, alloc, parallel_areas);
+                             0, 0, log_count - old_log_count, region_size,
+                             lv->le_count, allocatable_pvs,
+                             alloc, parallel_areas);
        if (!ah) {
                log_error("Unable to allocate extents for mirror log.");
                return 0;
        }
 
+       if (old_log_count) {
+               /* Converting from disk to mirrored log */
+               if (!_form_mirror(cmd, ah, log_lv, log_count - 1, 1, 0,
+                                 region_size, 1)) {
+                       log_error("Failed to convert mirror log");
+                       return 0;
+               }
+               r = 1;
+               goto out;
+       }
+
        /* check sync status */
-       if (lv_mirror_percent(cmd, lv, 0, &sync_percent, NULL) &&
-           (sync_percent == PERCENT_100))
+       if (mirror_in_sync() ||
+           (lv_mirror_percent(cmd, lv, 0, &sync_percent, NULL) &&
+            (sync_percent == PERCENT_100)))
                in_sync = 1;
        else
                in_sync = 0;
@@ -1871,7 +2007,7 @@ int add_mirror_images(struct cmd_context *cmd, struct logical_volume *lv,
         * allocate destination extents
         */
 
-       if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv, 0)))
+       if (!(parallel_areas = build_parallel_areas_from_lv(lv, 0)))
                return_0;
 
        if (!(segtype = get_segtype_from_string(cmd, "mirror")))
@@ -1941,8 +2077,11 @@ int lv_add_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
        }
 
        if (vg_is_clustered(lv->vg)) {
-               if (!(lv->status & ACTIVATE_EXCL) &&
-                   !cluster_mirror_is_available(lv)) {
+               /* FIXME: review check of lv_is_active_remotely */
+               /* FIXME: move this test out of this function */
+               /* Skip test for pvmove mirrors, it can use local mirror */
+               if (!(lv->status & (PVMOVE | LOCKED)) &&
+                   !_cluster_mirror_is_available(lv)) {
                        log_error("Shared cluster mirrors are not available.");
                        return 0;
                }
@@ -2008,7 +2147,7 @@ int lv_split_mirror_images(struct logical_volume *lv, const char *split_name,
        /* Can't split a mirror that is not in-sync... unless force? */
        if (!_mirrored_lv_in_sync(lv)) {
                log_error("Unable to split mirror that is not in-sync.");
-               return_0;
+               return 0;
        }
 
        /*
index e5bb9f0ac21c9eba5b412967fdc665f4a5f9d0fc..09b869b79897a8dfe11214b772f890aa8f670068 100644 (file)
@@ -143,23 +143,27 @@ uint32_t pv_mda_count(const struct physical_volume *pv)
 {
        struct lvmcache_info *info;
 
-       info = info_from_pvid((const char *)&pv->id.uuid, 0);
-       return info ? dm_list_size(&info->mdas) : UINT64_C(0);
+       info = lvmcache_info_from_pvid((const char *)&pv->id.uuid, 0);
+       return info ? lvmcache_mda_count(info) : UINT64_C(0);
+}
+
+static int _count_unignored(struct metadata_area *mda, void *baton)
+{
+       uint32_t *count = baton;
+       if (!mda_is_ignored(mda))
+               (*count) ++;
+       return 1;
 }
 
 uint32_t pv_mda_used_count(const struct physical_volume *pv)
 {
        struct lvmcache_info *info;
-       struct metadata_area *mda;
        uint32_t used_count=0;
 
-       info = info_from_pvid((const char *)&pv->id.uuid, 0);
+       info = lvmcache_info_from_pvid((const char *)&pv->id.uuid, 0);
        if (!info)
                return 0;
-       dm_list_iterate_items(mda, &info->mdas) {
-               if (!mda_is_ignored(mda))
-                       used_count++;
-       }
+       lvmcache_foreach_mda(info, _count_unignored, &used_count);
        return used_count;
 }
 
@@ -190,13 +194,15 @@ char *pv_attr_dup(struct dm_pool *mem, const struct physical_volume *pv)
 {
        char *repstr;
 
-       if (!(repstr = dm_pool_zalloc(mem, 3))) {
+       if (!(repstr = dm_pool_zalloc(mem, 4))) {
                log_error("dm_pool_alloc failed");
                return NULL;
        }
 
        repstr[0] = (pv->status & ALLOCATABLE_PV) ? 'a' : '-';
        repstr[1] = (pv->status & EXPORTED_VG) ? 'x' : '-';
+       repstr[2] = (pv->status & MISSING_PV) ? 'm' : '-';
+
        return repstr;
 }
 
@@ -207,29 +213,36 @@ uint64_t pv_mda_size(const struct physical_volume *pv)
        const char *pvid = (const char *)(&pv->id.uuid);
 
        /* PVs could have 2 mdas of different sizes (rounding effect) */
-       if ((info = info_from_pvid(pvid, 0)))
-               min_mda_size = find_min_mda_size(&info->mdas);
+       if ((info = lvmcache_info_from_pvid(pvid, 0)))
+               min_mda_size = lvmcache_smallest_mda_size(info);
        return min_mda_size;
 }
 
+static int _pv_mda_free(struct metadata_area *mda, void *baton) {
+       uint64_t mda_free;
+       uint64_t *freespace = baton;
+
+       if (!mda->ops->mda_free_sectors)
+               return 1;
+
+       mda_free = mda->ops->mda_free_sectors(mda);
+       if (mda_free < *freespace)
+               *freespace = mda_free;
+       return 1;
+}
+
 uint64_t pv_mda_free(const struct physical_volume *pv)
 {
        struct lvmcache_info *info;
-       uint64_t freespace = UINT64_MAX, mda_free;
+       uint64_t freespace = UINT64_MAX;
        const char *pvid = (const char *)&pv->id.uuid;
-       struct metadata_area *mda;
 
-       if ((info = info_from_pvid(pvid, 0)))
-               dm_list_iterate_items(mda, &info->mdas) {
-                       if (!mda->ops->mda_free_sectors)
-                               continue;
-                       mda_free = mda->ops->mda_free_sectors(mda);
-                       if (mda_free < freespace)
-                               freespace = mda_free;
-               }
+       if ((info = lvmcache_info_from_pvid(pvid, 0)))
+               lvmcache_foreach_mda(info, _pv_mda_free, &freespace);
 
        if (freespace == UINT64_MAX)
                freespace = UINT64_C(0);
+
        return freespace;
 }
 
@@ -244,18 +257,51 @@ uint64_t pv_used(const struct physical_volume *pv)
        return used;
 }
 
+struct _pv_mda_set_ignored_baton {
+       unsigned mda_ignored;
+       struct dm_list *mdas_in_use, *mdas_ignored, *mdas_to_change;
+};
+
+static int _pv_mda_set_ignored_one(struct metadata_area *mda, void *baton)
+{
+       struct _pv_mda_set_ignored_baton *b = baton;
+       struct metadata_area *vg_mda, *tmda;
+
+       if (mda_is_ignored(mda) && !b->mda_ignored) {
+               /* Changing an ignored mda to one in_use requires moving it */
+               dm_list_iterate_items_safe(vg_mda, tmda, b->mdas_ignored)
+                       if (mda_locns_match(mda, vg_mda)) {
+                               mda_set_ignored(vg_mda, b->mda_ignored);
+                               dm_list_move(b->mdas_in_use, &vg_mda->list);
+                       }
+       }
+
+       dm_list_iterate_items_safe(vg_mda, tmda, b->mdas_in_use)
+               if (mda_locns_match(mda, vg_mda))
+                       /* Don't move mda: needs writing to disk. */
+                       mda_set_ignored(vg_mda, b->mda_ignored);
+
+       mda_set_ignored(mda, b->mda_ignored);
+       return 1;
+}
+
 unsigned pv_mda_set_ignored(const struct physical_volume *pv, unsigned mda_ignored)
 {
        struct lvmcache_info *info;
-       struct metadata_area *mda, *vg_mda, *tmda;
-       struct dm_list *vg_mdas_in_use, *vg_mdas_ignored;
+       struct _pv_mda_set_ignored_baton baton;
+       struct metadata_area *mda;
 
-       if (!(info = info_from_pvid((const char *)&pv->id.uuid, 0)))
+       if (!(info = lvmcache_info_from_pvid((const char *)&pv->id.uuid, 0)))
                return_0;
 
+       baton.mda_ignored = mda_ignored;
+       baton.mdas_in_use = &pv->fid->metadata_areas_in_use;
+       baton.mdas_ignored = &pv->fid->metadata_areas_ignored;
+       baton.mdas_to_change = baton.mda_ignored ? baton.mdas_in_use : baton.mdas_ignored;
+
        if (is_orphan(pv)) {
-               dm_list_iterate_items(mda, &info->mdas)
-                       mda_set_ignored(mda, mda_ignored);
+               dm_list_iterate_items(mda, baton.mdas_to_change)
+                       mda_set_ignored(mda, baton.mda_ignored);
                return 1;
        }
 
@@ -279,25 +325,11 @@ unsigned pv_mda_set_ignored(const struct physical_volume *pv, unsigned mda_ignor
         * list, ensuring the new state will get written to disk in the
         * vg_write() path.
         */
-       vg_mdas_in_use = &pv->vg->fid->metadata_areas_in_use;
-       vg_mdas_ignored = &pv->vg->fid->metadata_areas_ignored;
-
-       dm_list_iterate_items(mda, &info->mdas) {
-               if (mda_is_ignored(mda) && !mda_ignored)
-                       /* Changing an ignored mda to one in_use requires moving it */
-                       dm_list_iterate_items_safe(vg_mda, tmda, vg_mdas_ignored)
-                               if (mda_locns_match(mda, vg_mda)) {
-                                       mda_set_ignored(vg_mda, mda_ignored);
-                                       dm_list_move(vg_mdas_in_use, &vg_mda->list);
-                               }
-
-               dm_list_iterate_items_safe(vg_mda, tmda, vg_mdas_in_use)
-                       if (mda_locns_match(mda, vg_mda))
-                               /* Don't move mda: needs writing to disk. */
-                               mda_set_ignored(vg_mda, mda_ignored);
-
-               mda_set_ignored(mda, mda_ignored);
-       }
+       /* FIXME: Try not to update the cache here! Also, try to iterate over
+        *        PV mdas only using the format instance's index somehow
+        *        (i.e. try to avoid using mda_locn_match call). */
+
+       lvmcache_foreach_mda(info, _pv_mda_set_ignored_one, &baton);
 
        return 1;
 }
index a02f6f8c962707bb6681f90ce826eafed690e7b6..b80472ad85db43f957ccce03f931c832f0c88785 100644 (file)
@@ -22,8 +22,10 @@ struct volume_group;
 
 struct physical_volume {
        struct id id;
+       struct id old_id;               /* Set during pvchange -u. */
        struct device *dev;
        const struct format_type *fmt;
+       struct format_instance *fid;
 
        /*
         * vg_name and vgid are used before the parent VG struct exists.
@@ -49,6 +51,12 @@ struct physical_volume {
        unsigned long pe_align;
        unsigned long pe_align_offset;
 
+        /* This is true whenever the represented PV has a label associated. */
+        uint64_t is_labelled:1;
+
+        /* NB. label_sector is valid whenever is_labelled is true */
+       uint64_t label_sector;
+
        struct dm_list segments;        /* Ordered pv_segments covering complete PV */
        struct dm_list tags;
 };
index d894f313c7eb002702795b70560be31f1fc1588e..23184734baebdc377a458a45b84dde74d2d5e376 100644 (file)
@@ -23,6 +23,7 @@ struct pv_segment *assign_peg_to_lvseg(struct physical_volume *pv, uint32_t pe,
 int pv_split_segment(struct dm_pool *mem,
                     struct physical_volume *pv, uint32_t pe,
                     struct pv_segment **pvseg_allocated);
+int discard_pv_segment(struct pv_segment *peg, uint32_t discard_area_reduction);
 int release_pv_segment(struct pv_segment *peg, uint32_t area_reduction);
 int check_pv_segments(struct volume_group *vg);
 void merge_pv_segments(struct pv_segment *peg1, struct pv_segment *peg2);
index e6fe6c2068899768120dbbf16aed2f3b0a0d5a44..d04ecabac6809f37cdbea796bfd0388145abfbe3 100644 (file)
@@ -17,9 +17,8 @@
 #include "metadata.h"
 #include "pv_alloc.h"
 #include "toolcontext.h"
-#include "archiver.h"
 #include "locking.h"
-#include "lvmcache.h"
+#include "defaults.h"
 
 static struct pv_segment *_alloc_pv_segment(struct dm_pool *mem,
                                            struct physical_volume *pv,
@@ -188,6 +187,61 @@ struct pv_segment *assign_peg_to_lvseg(struct physical_volume *pv,
        return peg;
 }
 
+int discard_pv_segment(struct pv_segment *peg, uint32_t discard_area_reduction)
+{
+       uint64_t discard_offset_sectors;
+       uint64_t pe_start = peg->pv->pe_start;
+       char uuid[64] __attribute__((aligned(8)));
+
+       if (!peg->lvseg) {
+               log_error("discard_pv_segment with unallocated segment: "
+                         "%s PE %" PRIu32, pv_dev_name(peg->pv), peg->pe);
+               return 0;
+       }
+
+       /*
+        * Only issue discards if enabled in lvm.conf and both
+        * the device and kernel (>= 2.6.35) supports discards.
+        */
+       if (!find_config_tree_bool(peg->pv->fmt->cmd,
+                                  "devices/issue_discards", DEFAULT_ISSUE_DISCARDS))
+               return 1;
+       /* Missing PV? */
+       if (is_missing_pv(peg->pv) || !peg->pv->dev) {
+               if (!id_write_format(&peg->pv->id, uuid, sizeof(uuid)))
+                       return_0;
+
+               log_verbose("Skipping discard on missing device with uuid %s.", uuid);
+
+               return 1;
+       }
+
+       if (!dev_discard_max_bytes(peg->pv->fmt->cmd->sysfs_dir, peg->pv->dev) ||
+           !dev_discard_granularity(peg->pv->fmt->cmd->sysfs_dir, peg->pv->dev))
+               return 1;
+
+       discard_offset_sectors = (peg->pe + peg->lvseg->area_len - discard_area_reduction) *
+                                (uint64_t) peg->pv->vg->extent_size + pe_start;
+       if (!discard_offset_sectors) {
+               /*
+                * pe_start=0 and the PV's first extent contains the label.
+                * Must skip past the first extent.
+                */
+               discard_offset_sectors = peg->pv->vg->extent_size;
+               discard_area_reduction--;
+       }
+
+       log_debug("Discarding %" PRIu32 " extents offset %" PRIu64 " sectors on %s.",
+                 discard_area_reduction, discard_offset_sectors, dev_name(peg->pv->dev));
+       if (discard_area_reduction &&
+           !dev_discard_blocks(peg->pv->dev, discard_offset_sectors << SECTOR_SHIFT,
+                               discard_area_reduction * (uint64_t) peg->pv->vg->extent_size * SECTOR_SIZE))
+               return_0;
+
+       return 1;
+}
+
 int release_pv_segment(struct pv_segment *peg, uint32_t area_reduction)
 {
        if (!peg->lvseg) {
@@ -357,10 +411,10 @@ int check_pv_segments(struct volume_group *vg)
        return ret;
 }
 
-static int _reduce_pv(struct physical_volume *pv, struct volume_group *vg, uint32_t new_pe_count)
+static int _reduce_pv(struct physical_volume *pv, struct volume_group *vg,
+                     uint32_t old_pe_count, uint32_t new_pe_count)
 {
        struct pv_segment *peg, *pegt;
-       uint32_t old_pe_count = pv->pe_count;
 
        if (new_pe_count < pv->pe_alloc_count) {
                log_error("%s: cannot resize to %" PRIu32 " extents "
@@ -400,10 +454,9 @@ static int _reduce_pv(struct physical_volume *pv, struct volume_group *vg, uint3
 }
 
 static int _extend_pv(struct physical_volume *pv, struct volume_group *vg,
-                     uint32_t new_pe_count)
+                     uint32_t old_pe_count, uint32_t new_pe_count)
 {
        struct pv_segment *peg;
-       uint32_t old_pe_count = pv->pe_count;
 
        if ((uint64_t) new_pe_count * pv->pe_size > pv->size ) {
                log_error("%s: cannot resize to %" PRIu32 " extents as there "
@@ -412,10 +465,12 @@ static int _extend_pv(struct physical_volume *pv, struct volume_group *vg,
                return 0;
        }
 
-       peg = _alloc_pv_segment(pv->fmt->cmd->mem, pv,
-                               old_pe_count,
-                               new_pe_count - old_pe_count,
-                               NULL, 0);
+       if (!(peg = _alloc_pv_segment(pv->fmt->cmd->mem, pv,
+                                     old_pe_count,
+                                     new_pe_count - old_pe_count,
+                                     NULL, 0)))
+               return_0;
+
        dm_list_add(&pv->segments, &peg->list);
 
        pv->pe_count = new_pe_count;
@@ -432,20 +487,59 @@ static int _extend_pv(struct physical_volume *pv, struct volume_group *vg,
  */
 int pv_resize(struct physical_volume *pv,
              struct volume_group *vg,
-             uint32_t new_pe_count)
+             uint64_t size)
 {
-       if ((new_pe_count == pv->pe_count)) {
-               log_verbose("No change to size of physical volume %s.",
-                           pv_dev_name(pv));
-               return 1;
+       uint32_t old_pe_count, new_pe_count = 0;
+
+       if (size < pv_min_size()) {
+               log_error("Size must exceed minimum of %" PRIu64 " sectors on PV %s.",
+                          pv_min_size(), pv_dev_name(pv));
+               return 0;
        }
 
-       log_verbose("Resizing physical volume %s from %" PRIu32
-                   " to %" PRIu32 " extents.",
-                   pv_dev_name(pv), pv->pe_count, new_pe_count);
+       if (size < pv_pe_start(pv)) {
+               log_error("Size must exceed physical extent start "
+                         "of %" PRIu64 " sectors on PV %s.",
+                         pv_pe_start(pv), pv_dev_name(pv));
+       }
 
-       if (new_pe_count > pv->pe_count)
-               return _extend_pv(pv, vg, new_pe_count);
-       else
-               return _reduce_pv(pv, vg, new_pe_count);
+       old_pe_count = pv->pe_count;
+
+       if (!pv->fmt->ops->pv_resize(pv->fmt, pv, vg, size)) {
+               log_error("Format specific resize of PV %s failed.",
+                          pv_dev_name(pv));
+               return 0;
+       }
+
+       /* pv->pe_count is 0 now! We need to recalculate! */
+
+       /* If there's a VG, calculate new PE count value. */
+       if (vg) {
+               /* FIXME: Maybe PE calculation should go into pv->fmt->resize?
+                         (like it is for pv->fmt->setup) */
+               if (!(new_pe_count = pv_size(pv) / vg->extent_size)) {
+                       log_error("Size must leave space for at least one physical "
+                                 "extent of %" PRIu32 " sectors on PV %s.",
+                                  pv_pe_size(pv), pv_dev_name(pv));
+                       return 0;
+               }
+
+               if (new_pe_count == old_pe_count) {
+                       pv->pe_count = old_pe_count;
+                       log_verbose("No change to size of physical volume %s.",
+                                   pv_dev_name(pv));
+                       return 1;
+               }
+
+               log_verbose("Resizing physical volume %s from %" PRIu32
+                           " to %" PRIu32 " extents.",
+                           pv_dev_name(pv), pv->pe_count, new_pe_count);
+
+               if (new_pe_count > old_pe_count)
+                       return _extend_pv(pv, vg, old_pe_count, new_pe_count);
+               else
+                       return _reduce_pv(pv, vg, old_pe_count, new_pe_count);
+       }
+
+       return 1;
 }
index 8ddb69858613de2f23261925cc7c7766cee6fd3f..48a601e93e66d57e23d6b47ec43935cbf76c717c 100644 (file)
@@ -15,7 +15,6 @@
 
 #include "lib.h"
 #include "pv_map.h"
-#include "pv_alloc.h"
 
 #include <assert.h>
 
@@ -205,10 +204,10 @@ void consume_pv_area(struct pv_area *pva, uint32_t to_go)
 }
 
 /*
- * Remove an area from list and reinsert it based on its new smaller size
- * after a provisional allocation.
+ * Remove an area from list and reinsert it based on its new size
+ * after a provisional allocation (or reverting one).
  */
-void reinsert_reduced_pv_area(struct pv_area *pva)
+void reinsert_changed_pv_area(struct pv_area *pva)
 {
        _remove_area(pva);
        _insert_area(&pva->map->areas, pva, 1);
index 4ebfd4a0440c490c8e0c306c8a6ec033f2d15f4e..79238c814d324e1fe54f54b9e7bd15687552357f 100644 (file)
@@ -31,7 +31,7 @@ struct pv_area {
        uint32_t start;
        uint32_t count;
 
-       /* Number of extents unreserved during ALLOC_ANYWHERE allocation. */
+       /* Number of extents unreserved during a single allocation pass. */
        uint32_t unreserved;
 
        struct dm_list list;            /* pv_map.areas */
@@ -66,7 +66,7 @@ struct dm_list *create_pv_maps(struct dm_pool *mem, struct volume_group *vg,
                            struct dm_list *allocatable_pvs);
 
 void consume_pv_area(struct pv_area *area, uint32_t to_go);
-void reinsert_reduced_pv_area(struct pv_area *pva);
+void reinsert_changed_pv_area(struct pv_area *pva);
 
 uint32_t pv_maps_size(struct dm_list *pvms);
 
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
new file mode 100644 (file)
index 0000000..c7910e8
--- /dev/null
@@ -0,0 +1,1843 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "lib.h"
+#include "metadata.h"
+#include "toolcontext.h"
+#include "segtype.h"
+#include "display.h"
+#include "activate.h"
+#include "lv_alloc.h"
+#include "lvm-string.h"
+
+#define RAID_REGION_SIZE 1024
+
+static int _lv_is_raid_with_tracking(const struct logical_volume *lv,
+                                    struct logical_volume **tracking)
+{
+       uint32_t s;
+       struct lv_segment *seg;
+
+       *tracking = NULL;
+       seg = first_seg(lv);
+
+       if (!(lv->status & RAID))
+               return 0;
+
+       for (s = 0; s < seg->area_count; s++)
+               if (lv_is_visible(seg_lv(seg, s)) &&
+                   !(seg_lv(seg, s)->status & LVM_WRITE))
+                       *tracking = seg_lv(seg, s);
+
+
+       return *tracking ? 1 : 0;
+}
+
+int lv_is_raid_with_tracking(const struct logical_volume *lv)
+{
+       struct logical_volume *tracking;
+
+       return _lv_is_raid_with_tracking(lv, &tracking);
+}
+
+uint32_t lv_raid_image_count(const struct logical_volume *lv)
+{
+       struct lv_segment *seg = first_seg(lv);
+
+       if (!seg_is_raid(seg))
+               return 1;
+
+       return seg->area_count;
+}
+
+/*
+ * Resume sub-LVs first, then top-level LV
+ */
+static int _bottom_up_resume(struct logical_volume *lv)
+{
+       uint32_t s;
+       struct lv_segment *seg = first_seg(lv);
+
+       if (seg_is_raid(seg) && (seg->area_count > 1)) {
+               for (s = 0; s < seg->area_count; s++)
+                       if (!resume_lv(lv->vg->cmd, seg_lv(seg, s)) ||
+                           !resume_lv(lv->vg->cmd, seg_metalv(seg, s)))
+                               return_0;
+       }
+
+       return resume_lv(lv->vg->cmd, lv);
+}
+
+static int _activate_sublv_preserving_excl(struct logical_volume *top_lv,
+                                          struct logical_volume *sub_lv)
+{
+       struct cmd_context *cmd = top_lv->vg->cmd;
+
+       /* If top RAID was EX, use EX */
+       if (lv_is_active_exclusive_locally(top_lv)) {
+               if (!activate_lv_excl(cmd, sub_lv))
+                       return_0;
+       } else {
+               if (!activate_lv(cmd, sub_lv))
+                       return_0;
+       }
+       return 1;
+}
+
+/*
+ * _lv_is_on_pv
+ * @lv:
+ * @pv:
+ *
+ * If any of the component devices of the LV are on the given PV, 1
+ * is returned; otherwise 0.  For example if one of the images of a RAID
+ * (or its metadata device) is on the PV, 1 would be returned for the
+ * top-level LV.
+ * If you wish to check the images themselves, you should pass them.
+ *
+ * FIXME:  This should be made more generic, possibly use 'for_each_sub_lv',
+ * and be put in lv_manip.c.  'for_each_sub_lv' does not yet allow us to
+ * short-circuit execution or pass back the values we need yet though...
+ */
+static int _lv_is_on_pv(struct logical_volume *lv, struct physical_volume *pv)
+{
+       uint32_t s;
+       struct physical_volume *pv2;
+       struct lv_segment *seg;
+
+       if (!lv)
+               return 0;
+
+       seg = first_seg(lv);
+       if (!seg)
+               return 0;
+
+       /* Check mirror log */
+       if (_lv_is_on_pv(seg->log_lv, pv))
+               return 1;
+
+       /* Check stack of LVs */
+       dm_list_iterate_items(seg, &lv->segments) {
+               for (s = 0; s < seg->area_count; s++) {
+                       if (seg_type(seg, s) == AREA_PV) {
+                               pv2 = seg_pv(seg, s);
+                               if (id_equal(&pv->id, &pv2->id))
+                                       return 1;
+                               if (pv->dev && pv2->dev &&
+                                   (pv->dev->dev == pv2->dev->dev))
+                                       return 1;
+                       }
+
+                       if ((seg_type(seg, s) == AREA_LV) &&
+                           _lv_is_on_pv(seg_lv(seg, s), pv))
+                               return 1;
+
+                       if (!seg_is_raid(seg))
+                               continue;
+
+                       /* This is RAID, so we know the meta_area is AREA_LV */
+                       if (_lv_is_on_pv(seg_metalv(seg, s), pv))
+                               return 1;
+               }
+       }
+
+       return 0;
+}
+
+static int _lv_is_on_pvs(struct logical_volume *lv, struct dm_list *pvs)
+{
+       struct pv_list *pvl;
+
+       dm_list_iterate_items(pvl, pvs)
+               if (_lv_is_on_pv(lv, pvl->pv)) {
+                       log_debug("%s is on %s", lv->name,
+                                 pv_dev_name(pvl->pv));
+                       return 1;
+               } else
+                       log_debug("%s is not on %s", lv->name,
+                                 pv_dev_name(pvl->pv));
+       return 0;
+}
+
+static int _get_pv_list_for_lv(struct logical_volume *lv, struct dm_list *pvs)
+{
+       uint32_t s;
+       struct pv_list *pvl;
+       struct lv_segment *seg = first_seg(lv);
+
+       if (!seg_is_linear(seg)) {
+               log_error(INTERNAL_ERROR
+                         "_get_pv_list_for_lv only handles linear volumes");
+               return 0;
+       }
+
+       log_debug("Getting list of PVs that %s/%s is on:",
+                 lv->vg->name, lv->name);
+
+       dm_list_iterate_items(seg, &lv->segments) {
+               for (s = 0; s < seg->area_count; s++) {
+                       if (seg_type(seg, s) != AREA_PV) {
+                               log_error(INTERNAL_ERROR
+                                         "Linear seg_type should be AREA_PV");
+                               return 0;
+                       }
+
+                       if (!(pvl = dm_pool_zalloc(lv->vg->cmd->mem,
+                                                  sizeof(*pvl)))) {
+                               log_error("Failed to allocate memory");
+                               return 0;
+                       }
+
+                       pvl->pv = seg_pv(seg, s);
+                       log_debug("  %s/%s is on %s", lv->vg->name, lv->name,
+                                 pv_dev_name(pvl->pv));
+                       dm_list_add(pvs, &pvl->list);
+               }
+       }
+
+       return 1;
+}
+
+/*
+ * _raid_in_sync
+ * @lv
+ *
+ * _raid_in_sync works for all types of RAID segtypes, as well
+ * as 'mirror' segtype.  (This is because 'lv_raid_percent' is
+ * simply a wrapper around 'lv_mirror_percent'.
+ *
+ * Returns: 1 if in-sync, 0 otherwise.
+ */
+static int _raid_in_sync(struct logical_volume *lv)
+{
+       percent_t sync_percent;
+
+       if (!lv_raid_percent(lv, &sync_percent)) {
+               log_error("Unable to determine sync status of %s/%s.",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       return (sync_percent == PERCENT_100) ? 1 : 0;
+}
+
+/*
+ * _raid_remove_top_layer
+ * @lv
+ * @removal_list
+ *
+ * Remove top layer of RAID LV in order to convert to linear.
+ * This function makes no on-disk changes.  The residual LVs
+ * returned in 'removal_list' must be freed by the caller.
+ *
+ * Returns: 1 on succes, 0 on failure
+ */
+static int _raid_remove_top_layer(struct logical_volume *lv,
+                                 struct dm_list *removal_list)
+{
+       struct lv_list *lvl_array, *lvl;
+       struct lv_segment *seg = first_seg(lv);
+
+       if (!seg_is_mirrored(seg)) {
+               log_error(INTERNAL_ERROR
+                         "Unable to remove RAID layer from segment type %s",
+                         seg->segtype->ops->name(seg));
+               return 0;
+       }
+
+       if (seg->area_count != 1) {
+               log_error(INTERNAL_ERROR
+                         "Unable to remove RAID layer when there"
+                         " is more than one sub-lv");
+               return 0;
+       }
+
+       lvl_array = dm_pool_alloc(lv->vg->vgmem, 2 * sizeof(*lvl));
+       if (!lvl_array) {
+               log_error("Memory allocation failed.");
+               return 0;
+       }
+
+       /* Add last metadata area to removal_list */
+       lvl_array[0].lv = seg_metalv(seg, 0);
+       lv_set_visible(seg_metalv(seg, 0));
+       remove_seg_from_segs_using_this_lv(seg_metalv(seg, 0), seg);
+       seg_metatype(seg, 0) = AREA_UNASSIGNED;
+       dm_list_add(removal_list, &(lvl_array[0].list));
+
+       /* Remove RAID layer and add residual LV to removal_list*/
+       seg_lv(seg, 0)->status &= ~RAID_IMAGE;
+       lv_set_visible(seg_lv(seg, 0));
+       lvl_array[1].lv = seg_lv(seg, 0);
+       dm_list_add(removal_list, &(lvl_array[1].list));
+
+       if (!remove_layer_from_lv(lv, seg_lv(seg, 0)))
+               return_0;
+
+       lv->status &= ~(MIRRORED | RAID);
+       return 1;
+}
+
+/*
+ * _clear_lv
+ * @lv
+ *
+ * If LV is active:
+ *        clear first block of device
+ * otherwise:
+ *        activate, clear, deactivate
+ *
+ * Returns: 1 on success, 0 on failure
+ */
+static int _clear_lv(struct logical_volume *lv)
+{
+       int was_active = lv_is_active(lv);
+
+       if (test_mode())
+               return 1;
+
+       if (!was_active && !activate_lv(lv->vg->cmd, lv)) {
+               log_error("Failed to activate %s for clearing",
+                         lv->name);
+               return 0;
+       }
+
+       log_verbose("Clearing metadata area of %s/%s",
+                   lv->vg->name, lv->name);
+       /*
+        * Rather than wiping lv->size, we can simply
+        * wipe the first sector to remove the superblock of any previous
+        * RAID devices.  It is much quicker.
+        */
+       if (!set_lv(lv->vg->cmd, lv, 1, 0)) {
+               log_error("Failed to zero %s", lv->name);
+               return 0;
+       }
+
+       if (!was_active && !deactivate_lv(lv->vg->cmd, lv)) {
+               log_error("Failed to deactivate %s", lv->name);
+               return 0;
+       }
+
+       return 1;
+}
+
+/* Makes on-disk metadata changes */
+static int _clear_lvs(struct dm_list *lv_list)
+{
+       struct lv_list *lvl;
+       struct volume_group *vg = NULL;
+
+       if (dm_list_empty(lv_list)) {
+               log_debug(INTERNAL_ERROR "Empty list of LVs given for clearing");
+               return 1;
+       }
+
+       dm_list_iterate_items(lvl, lv_list) {
+               if (!lv_is_visible(lvl->lv)) {
+                       log_error(INTERNAL_ERROR
+                                 "LVs must be set visible before clearing");
+                       return 0;
+               }
+               vg = lvl->lv->vg;
+       }
+
+       /*
+        * FIXME: only vg_[write|commit] if LVs are not already written
+        * as visible in the LVM metadata (which is never the case yet).
+        */
+       if (!vg || !vg_write(vg) || !vg_commit(vg))
+               return_0;
+
+       dm_list_iterate_items(lvl, lv_list)
+               if (!_clear_lv(lvl->lv))
+                       return 0;
+
+       return 1;
+}
+
+/*
+ * _shift_and_rename_image_components
+ * @seg: Top-level RAID segment
+ *
+ * Shift all higher indexed segment areas down to fill in gaps where
+ * there are 'AREA_UNASSIGNED' areas and rename data/metadata LVs so
+ * that their names match their new index.  When finished, set
+ * seg->area_count to new reduced total.
+ *
+ * Returns: 1 on success, 0 on failure
+ */
+static int _shift_and_rename_image_components(struct lv_segment *seg)
+{
+       int len;
+       char *shift_name;
+       uint32_t s, missing;
+       struct cmd_context *cmd = seg->lv->vg->cmd;
+
+       /*
+        * All LVs must be properly named for their index before
+        * shifting begins.  (e.g.  Index '0' must contain *_rimage_0 and
+        * *_rmeta_0.  Index 'n' must contain *_rimage_n and *_rmeta_n.)
+        */
+
+       if (!seg_is_raid(seg))
+               return_0;
+
+       if (seg->area_count > 10) {
+               /*
+                * FIXME: Handling more would mean I'd have
+                * to handle double digits
+                */
+               log_error("Unable handle arrays with more than 10 devices");
+               return 0;
+       }
+
+       log_very_verbose("Shifting images in %s", seg->lv->name);
+
+       for (s = 0, missing = 0; s < seg->area_count; s++) {
+               if (seg_type(seg, s) == AREA_UNASSIGNED) {
+                       if (seg_metatype(seg, s) != AREA_UNASSIGNED) {
+                               log_error(INTERNAL_ERROR "Metadata segment area"
+                                         " #%d should be AREA_UNASSIGNED", s);
+                               return 0;
+                       }
+                       missing++;
+                       continue;
+               }
+               if (!missing)
+                       continue;
+
+               log_very_verbose("Shifting %s and %s by %u",
+                                seg_metalv(seg, s)->name,
+                                seg_lv(seg, s)->name, missing);
+
+               /* Alter rmeta name */
+               shift_name = dm_pool_strdup(cmd->mem, seg_metalv(seg, s)->name);
+               if (!shift_name) {
+                       log_error("Memory allocation failed.");
+                       return 0;
+               }
+               len = strlen(shift_name) - 1;
+               shift_name[len] -= missing;
+               seg_metalv(seg, s)->name = shift_name;
+
+               /* Alter rimage name */
+               shift_name = dm_pool_strdup(cmd->mem, seg_lv(seg, s)->name);
+               if (!shift_name) {
+                       log_error("Memory allocation failed.");
+                       return 0;
+               }
+               len = strlen(shift_name) - 1;
+               shift_name[len] -= missing;
+               seg_lv(seg, s)->name = shift_name;
+
+               seg->areas[s - missing] = seg->areas[s];
+               seg->meta_areas[s - missing] = seg->meta_areas[s];
+       }
+
+       seg->area_count -= missing;
+       return 1;
+}
+
+/*
+ * Create an LV of specified type.  Set visible after creation.
+ * This function does not make metadata changes.
+ */
+static int _alloc_image_component(struct logical_volume *lv,
+                                 const char *alt_base_name,
+                                 struct alloc_handle *ah, uint32_t first_area,
+                                 uint64_t type, struct logical_volume **new_lv)
+{
+       uint64_t status;
+       size_t len = strlen(lv->name) + 32;
+       char img_name[len];
+       const char *base_name = (alt_base_name) ? alt_base_name : lv->name;
+       struct logical_volume *tmp_lv;
+       const struct segment_type *segtype;
+
+       if (type == RAID_META) {
+               if (dm_snprintf(img_name, len, "%s_rmeta_%%d", base_name) < 0)
+                       return_0;
+       } else if (type == RAID_IMAGE) {
+               if (dm_snprintf(img_name, len, "%s_rimage_%%d", base_name) < 0)
+                       return_0;
+       } else {
+               log_error(INTERNAL_ERROR
+                         "Bad type provided to _alloc_raid_component");
+               return 0;
+       }
+
+       if (!ah) {
+               first_area = 0;
+               log_error(INTERNAL_ERROR
+                         "Stand-alone %s area allocation not implemented",
+                         (type == RAID_META) ? "metadata" : "data");
+               return 0;
+       }
+
+       status = LVM_READ | LVM_WRITE | LV_REBUILD | type;
+       tmp_lv = lv_create_empty(img_name, NULL, status, ALLOC_INHERIT, lv->vg);
+       if (!tmp_lv) {
+               log_error("Failed to allocate new raid component, %s", img_name);
+               return 0;
+       }
+
+       segtype = get_segtype_from_string(lv->vg->cmd, "striped");
+       if (!lv_add_segment(ah, first_area, 1, tmp_lv, segtype, 0, status, 0)) {
+               log_error("Failed to add segment to LV, %s", img_name);
+               return 0;
+       }
+
+       lv_set_visible(tmp_lv);
+       *new_lv = tmp_lv;
+       return 1;
+}
+
+static int _alloc_image_components(struct logical_volume *lv,
+                                  struct dm_list *pvs, uint32_t count,
+                                  struct dm_list *new_meta_lvs,
+                                  struct dm_list *new_data_lvs)
+{
+       uint32_t s;
+       uint32_t region_size;
+       uint32_t extents;
+       struct lv_segment *seg = first_seg(lv);
+       const struct segment_type *segtype;
+       struct alloc_handle *ah;
+       struct dm_list *parallel_areas;
+       struct logical_volume *tmp_lv;
+       struct lv_list *lvl_array;
+
+       lvl_array = dm_pool_alloc(lv->vg->vgmem,
+                                 sizeof(*lvl_array) * count * 2);
+       if (!lvl_array)
+               return_0;
+
+       if (!(parallel_areas = build_parallel_areas_from_lv(lv, 0)))
+               return_0;
+
+       if (seg_is_linear(seg))
+               region_size = RAID_REGION_SIZE;
+       else
+               region_size = seg->region_size;
+
+       if (seg_is_raid(seg))
+               segtype = seg->segtype;
+       else if (!(segtype = get_segtype_from_string(lv->vg->cmd, "raid1")))
+               return_0;
+
+       /*
+        * The number of extents is based on the RAID type.  For RAID1,
+        * each of the rimages is the same size - 'le_count'.  However
+        * for RAID 4/5/6, the stripes add together (NOT including the parity
+        * devices) to equal 'le_count'.  Thus, when we are allocating
+        * individual devies, we must specify how large the individual device
+        * is along with the number we want ('count').
+        */
+       extents = (segtype->parity_devs) ?
+               (lv->le_count / (seg->area_count - segtype->parity_devs)) :
+               lv->le_count;
+
+       if (!(ah = allocate_extents(lv->vg, NULL, segtype, 0, count, count,
+                                   region_size, extents, pvs,
+                                   lv->alloc, parallel_areas)))
+               return_0;
+
+       for (s = 0; s < count; s++) {
+               /*
+                * The allocation areas are grouped together.  First
+                * come the rimage allocated areas, then come the metadata
+                * allocated areas.  Thus, the metadata areas are pulled
+                * from 's + count'.
+                */
+               if (!_alloc_image_component(lv, NULL, ah, s + count,
+                                           RAID_META, &tmp_lv))
+                       return_0;
+               lvl_array[s + count].lv = tmp_lv;
+               dm_list_add(new_meta_lvs, &(lvl_array[s + count].list));
+
+               if (!_alloc_image_component(lv, NULL, ah, s,
+                                           RAID_IMAGE, &tmp_lv))
+                       return_0;
+               lvl_array[s].lv = tmp_lv;
+               dm_list_add(new_data_lvs, &(lvl_array[s].list));
+       }
+       alloc_destroy(ah);
+       return 1;
+}
+
+/*
+ * _alloc_rmeta_for_lv
+ * @lv
+ *
+ * Allocate a RAID metadata device for the given LV (which is or will
+ * be the associated RAID data device).  The new metadata device must
+ * be allocated from the same PV(s) as the data device.
+ */
+static int _alloc_rmeta_for_lv(struct logical_volume *data_lv,
+                              struct logical_volume **meta_lv)
+{
+       struct dm_list allocatable_pvs;
+       struct alloc_handle *ah;
+       struct lv_segment *seg = first_seg(data_lv);
+       char *p, base_name[strlen(data_lv->name) + 1];
+
+       dm_list_init(&allocatable_pvs);
+
+       if (!seg_is_linear(seg)) {
+               log_error(INTERNAL_ERROR "Unable to allocate RAID metadata "
+                         "area for non-linear LV, %s", data_lv->name);
+               return 0;
+       }
+
+       sprintf(base_name, "%s", data_lv->name);
+       if ((p = strstr(base_name, "_mimage_")))
+               *p = '\0';
+
+       if (!_get_pv_list_for_lv(data_lv, &allocatable_pvs)) {
+               log_error("Failed to build list of PVs for %s/%s",
+                         data_lv->vg->name, data_lv->name);
+               return 0;
+       }
+
+       if (!(ah = allocate_extents(data_lv->vg, NULL, seg->segtype, 0, 1, 0,
+                                   seg->region_size,
+                                   1 /*RAID_METADATA_AREA_LEN*/,
+                                   &allocatable_pvs, data_lv->alloc, NULL)))
+               return_0;
+
+       if (!_alloc_image_component(data_lv, base_name, ah, 0,
+                                   RAID_META, meta_lv))
+               return_0;
+
+       alloc_destroy(ah);
+       return 1;
+}
+
+static int _raid_add_images(struct logical_volume *lv,
+                           uint32_t new_count, struct dm_list *pvs)
+{
+       int rebuild_flag_cleared = 0;
+       uint32_t s;
+       uint32_t old_count = lv_raid_image_count(lv);
+       uint32_t count = new_count - old_count;
+       uint64_t status_mask = -1;
+       struct cmd_context *cmd = lv->vg->cmd;
+       struct lv_segment *seg = first_seg(lv);
+       struct dm_list meta_lvs, data_lvs;
+       struct lv_list *lvl;
+       struct lv_segment_area *new_areas;
+
+       if (lv->status & LV_NOTSYNCED) {
+               log_error("Can't add image to out-of-sync RAID LV:"
+                         " use 'lvchange --resync' first.");
+               return 0;
+       }
+
+       if (!_raid_in_sync(lv)) {
+               log_error("Can't add image to RAID LV that"
+                         " is still initializing.");
+               return 0;
+       }
+
+       dm_list_init(&meta_lvs); /* For image addition */
+       dm_list_init(&data_lvs); /* For image addition */
+
+       /*
+        * If the segtype is linear, then we must allocate a metadata
+        * LV to accompany it.
+        */
+       if (seg_is_linear(seg)) {
+               /* A complete resync will be done, no need to mark each sub-lv */
+               status_mask = ~(LV_REBUILD);
+
+               if (!(lvl = dm_pool_alloc(lv->vg->vgmem, sizeof(*lvl)))) {
+                       log_error("Memory allocation failed");
+                       return 0;
+               }
+
+               if (!_alloc_rmeta_for_lv(lv, &lvl->lv))
+                       return_0;
+
+               dm_list_add(&meta_lvs, &lvl->list);
+       } else if (!seg_is_raid(seg)) {
+               log_error("Unable to add RAID images to %s of segment type %s",
+                         lv->name, seg->segtype->ops->name(seg));
+               return 0;
+       } else if (!_raid_in_sync(lv)) {
+               log_error("Unable to add RAID images until %s is in-sync",
+                         lv->name);
+               return 0;
+       }
+
+       if (!_alloc_image_components(lv, pvs, count, &meta_lvs, &data_lvs)) {
+               log_error("Failed to allocate new image components");
+               return 0;
+       }
+
+       /*
+        * If linear, we must correct data LV names.  They are off-by-one
+        * because the linear volume hasn't taken its proper name of "_rimage_0"
+        * yet.  This action must be done before '_clear_lvs' because it
+        * commits the LVM metadata before clearing the LVs.
+        */
+       if (seg_is_linear(seg)) {
+               char *name;
+               size_t len;
+               struct dm_list *l;
+               struct lv_list *lvl_tmp;
+
+               dm_list_iterate(l, &data_lvs) {
+                       if (l == dm_list_last(&data_lvs)) {
+                               lvl = dm_list_item(l, struct lv_list);
+                               len = strlen(lv->name) + strlen("_rimage_XXX");
+                               if (!(name = dm_pool_alloc(lv->vg->vgmem, len))) {
+                                       log_error("Failed to allocate rimage name.");
+                                       return 0;
+                               }
+                               sprintf(name, "%s_rimage_%u", lv->name, count);
+                               lvl->lv->name = name;
+                               continue;
+                       }
+                       lvl = dm_list_item(l, struct lv_list);
+                       lvl_tmp = dm_list_item(l->n, struct lv_list);
+                       lvl->lv->name = lvl_tmp->lv->name;
+               }
+       }
+
+       /* Metadata LVs must be cleared before being added to the array */
+       if (!_clear_lvs(&meta_lvs))
+               goto fail;
+
+       if (seg_is_linear(seg)) {
+               first_seg(lv)->status |= RAID_IMAGE;
+               if (!insert_layer_for_lv(lv->vg->cmd, lv,
+                                        RAID | LVM_READ | LVM_WRITE,
+                                        "_rimage_0"))
+                       return_0;
+
+               lv->status |= RAID;
+               seg = first_seg(lv);
+               seg_lv(seg, 0)->status |= RAID_IMAGE | LVM_READ | LVM_WRITE;
+               seg->region_size = RAID_REGION_SIZE;
+               /* MD's bitmap is limited to tracking 2^21 regions */
+               while (seg->region_size < (lv->size / (1 << 21))) {
+                       seg->region_size *= 2;
+                       log_very_verbose("Setting RAID1 region_size to %uS",
+                                        seg->region_size);
+               }
+               seg->segtype = get_segtype_from_string(lv->vg->cmd, "raid1");
+               if (!seg->segtype)
+                       return_0;
+       }
+/*
+FIXME: It would be proper to activate the new LVs here, instead of having
+them activated by the suspend.  However, this causes residual device nodes
+to be left for these sub-lvs.
+       dm_list_iterate_items(lvl, &meta_lvs)
+               if (!do_correct_activate(lv, lvl->lv))
+                       return_0;
+       dm_list_iterate_items(lvl, &data_lvs)
+               if (!do_correct_activate(lv, lvl->lv))
+                       return_0;
+*/
+       /* Expand areas array */
+       if (!(new_areas = dm_pool_zalloc(lv->vg->cmd->mem,
+                                        new_count * sizeof(*new_areas))))
+               goto fail;
+       memcpy(new_areas, seg->areas, seg->area_count * sizeof(*seg->areas));
+       seg->areas = new_areas;
+
+       /* Expand meta_areas array */
+       if (!(new_areas = dm_pool_zalloc(lv->vg->cmd->mem,
+                                        new_count * sizeof(*new_areas))))
+               goto fail;
+       if (seg->meta_areas)
+               memcpy(new_areas, seg->meta_areas,
+                      seg->area_count * sizeof(*seg->meta_areas));
+       seg->meta_areas = new_areas;
+       seg->area_count = new_count;
+
+       /* Add extra meta area when converting from linear */
+       s = (old_count == 1) ? 0 : old_count;
+
+       /* Set segment areas for metadata sub_lvs */
+       dm_list_iterate_items(lvl, &meta_lvs) {
+               log_debug("Adding %s to %s",
+                         lvl->lv->name, lv->name);
+               lvl->lv->status &= status_mask;
+               first_seg(lvl->lv)->status &= status_mask;
+               if (!set_lv_segment_area_lv(seg, s, lvl->lv, 0,
+                                           lvl->lv->status)) {
+                       log_error("Failed to add %s to %s",
+                                 lvl->lv->name, lv->name);
+                       goto fail;
+               }
+               s++;
+       }
+
+       s = old_count;
+
+       /* Set segment areas for data sub_lvs */
+       dm_list_iterate_items(lvl, &data_lvs) {
+               log_debug("Adding %s to %s",
+                         lvl->lv->name, lv->name);
+               lvl->lv->status &= status_mask;
+               first_seg(lvl->lv)->status &= status_mask;
+               if (!set_lv_segment_area_lv(seg, s, lvl->lv, 0,
+                                           lvl->lv->status)) {
+                       log_error("Failed to add %s to %s",
+                                 lvl->lv->name, lv->name);
+                       goto fail;
+               }
+               s++;
+       }
+
+       /*
+        * FIXME: Failure handling during these points is harder.
+        */
+       dm_list_iterate_items(lvl, &meta_lvs)
+               lv_set_hidden(lvl->lv);
+       dm_list_iterate_items(lvl, &data_lvs)
+               lv_set_hidden(lvl->lv);
+
+       if (!vg_write(lv->vg)) {
+               log_error("Failed to write changes to %s in %s",
+                         lv->name, lv->vg->name);
+               return 0;
+       }
+
+       if (!suspend_lv_origin(cmd, lv)) {
+               log_error("Failed to suspend %s/%s before committing changes",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       if (!vg_commit(lv->vg)) {
+               log_error("Failed to commit changes to %s in %s",
+                         lv->name, lv->vg->name);
+               return 0;
+       }
+
+       if (!resume_lv_origin(cmd, lv)) {
+               log_error("Failed to resume %s/%s after committing changes",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       /*
+        * Now that the 'REBUILD' has made its way to the kernel, we must
+        * remove the flag so that the individual devices are not rebuilt
+        * upon every activation.
+        */
+       seg = first_seg(lv);
+       for (s = 0; s < seg->area_count; s++) {
+               if ((seg_lv(seg, s)->status & LV_REBUILD) ||
+                   (seg_metalv(seg, s)->status & LV_REBUILD)) {
+                       seg_metalv(seg, s)->status &= ~LV_REBUILD;
+                       seg_lv(seg, s)->status &= ~LV_REBUILD;
+                       rebuild_flag_cleared = 1;
+               }
+       }
+       if (rebuild_flag_cleared &&
+           (!vg_write(lv->vg) || !vg_commit(lv->vg))) {
+               log_error("Failed to clear REBUILD flag for %s/%s components",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       return 1;
+
+fail:
+       /* Cleanly remove newly-allocated LVs that failed insertion attempt */
+
+       dm_list_iterate_items(lvl, &meta_lvs)
+               if (!lv_remove(lvl->lv))
+                       return_0;
+       dm_list_iterate_items(lvl, &data_lvs)
+               if (!lv_remove(lvl->lv))
+                       return_0;
+       return_0;
+}
+
+/*
+ * _extract_image_components
+ * @seg
+ * @idx:  The index in the areas array to remove
+ * @extracted_rmeta:  The displaced metadata LV
+ * @extracted_rimage:  The displaced data LV
+ *
+ * This function extracts the image components - setting the respective
+ * 'extracted' pointers.  It appends '_extracted' to the LVs' names, so that
+ * there are not future conflicts.  It does /not/ commit the results.
+ * (IOW, erroring-out requires no unwinding of operations.)
+ *
+ * This function does /not/ attempt to:
+ *    1) shift the 'areas' or 'meta_areas' arrays.
+ *       The '[meta_]areas' are left as AREA_UNASSIGNED.
+ *    2) Adjust the seg->area_count
+ *    3) Name the extracted LVs appropriately (appends '_extracted' to names)
+ * These actions must be performed by the caller.
+ *
+ * Returns: 1 on success, 0 on failure
+ */
+static int _extract_image_components(struct lv_segment *seg, uint32_t idx,
+                                    struct logical_volume **extracted_rmeta,
+                                    struct logical_volume **extracted_rimage)
+{
+       int len;
+       char *tmp_name;
+       struct volume_group *vg = seg->lv->vg;
+       struct logical_volume *data_lv = seg_lv(seg, idx);
+       struct logical_volume *meta_lv = seg_metalv(seg, idx);
+
+       log_very_verbose("Extracting image components %s and %s from %s",
+                        data_lv->name, meta_lv->name, seg->lv->name);
+
+       data_lv->status &= ~RAID_IMAGE;
+       meta_lv->status &= ~RAID_META;
+       lv_set_visible(data_lv);
+       lv_set_visible(meta_lv);
+
+       /* release removes data and meta areas */
+       remove_seg_from_segs_using_this_lv(data_lv, seg);
+       remove_seg_from_segs_using_this_lv(meta_lv, seg);
+
+       seg_type(seg, idx) = AREA_UNASSIGNED;
+       seg_metatype(seg, idx) = AREA_UNASSIGNED;
+
+       len = strlen(meta_lv->name) + strlen("_extracted") + 1;
+       tmp_name = dm_pool_alloc(vg->vgmem, len);
+       if (!tmp_name)
+               return_0;
+       sprintf(tmp_name, "%s_extracted", meta_lv->name);
+       meta_lv->name = tmp_name;
+
+       len = strlen(data_lv->name) + strlen("_extracted") + 1;
+       tmp_name = dm_pool_alloc(vg->vgmem, len);
+       if (!tmp_name)
+               return_0;
+       sprintf(tmp_name, "%s_extracted", data_lv->name);
+       data_lv->name = tmp_name;
+
+       *extracted_rmeta = meta_lv;
+       *extracted_rimage = data_lv;
+
+       return 1;
+}
+
+/*
+ * _raid_extract_images
+ * @lv
+ * @new_count:  The absolute count of images (e.g. '2' for a 2-way mirror)
+ * @target_pvs:  The list of PVs that are candidates for removal
+ * @shift:  If set, use _shift_and_rename_image_components().
+ *          Otherwise, leave the [meta_]areas as AREA_UNASSIGNED and
+ *          seg->area_count unchanged.
+ * @extracted_[meta|data]_lvs:  The LVs removed from the array.  If 'shift'
+ *                              is set, then there will likely be name conflicts.
+ *
+ * This function extracts _both_ portions of the indexed image.  It
+ * does /not/ commit the results.  (IOW, erroring-out requires no unwinding
+ * of operations.)
+ *
+ * Returns: 1 on success, 0 on failure
+ */
+static int _raid_extract_images(struct logical_volume *lv, uint32_t new_count,
+                               struct dm_list *target_pvs, int shift,
+                               struct dm_list *extracted_meta_lvs,
+                               struct dm_list *extracted_data_lvs)
+{
+       int s, extract, lvl_idx = 0;
+       struct lv_list *lvl_array;
+       struct lv_segment *seg = first_seg(lv);
+       struct logical_volume *rmeta_lv, *rimage_lv;
+
+       extract = seg->area_count - new_count;
+       log_verbose("Extracting %u %s from %s/%s", extract,
+                   (extract > 1) ? "images" : "image",
+                   lv->vg->name, lv->name);
+
+       lvl_array = dm_pool_alloc(lv->vg->vgmem,
+                                 sizeof(*lvl_array) * extract * 2);
+       if (!lvl_array)
+               return_0;
+
+       for (s = seg->area_count - 1; (s >= 0) && extract; s--) {
+               if (!_lv_is_on_pvs(seg_lv(seg, s), target_pvs) ||
+                   !_lv_is_on_pvs(seg_metalv(seg, s), target_pvs))
+                       continue;
+               if (!_raid_in_sync(lv) &&
+                   (!seg_is_mirrored(seg) || (s == 0))) {
+                       log_error("Unable to extract %sRAID image"
+                                 " while RAID array is not in-sync",
+                                 seg_is_mirrored(seg) ? "primary " : "");
+                       return 0;
+               }
+
+               if (!_extract_image_components(seg, s, &rmeta_lv, &rimage_lv)) {
+                       log_error("Failed to extract %s from %s",
+                                 seg_lv(seg, s)->name, lv->name);
+                       return 0;
+               }
+
+               if (shift && !_shift_and_rename_image_components(seg)) {
+                       log_error("Failed to shift and rename image components");
+                       return 0;
+               }
+
+               lvl_array[lvl_idx].lv = rmeta_lv;
+               lvl_array[lvl_idx + 1].lv = rimage_lv;
+               dm_list_add(extracted_meta_lvs, &(lvl_array[lvl_idx++].list));
+               dm_list_add(extracted_data_lvs, &(lvl_array[lvl_idx++].list));
+
+               extract--;
+       }
+       if (extract) {
+               log_error("Unable to extract enough images to satisfy request");
+               return 0;
+       }
+
+       return 1;
+}
+
+static int _raid_remove_images(struct logical_volume *lv,
+                              uint32_t new_count, struct dm_list *pvs)
+{
+       struct dm_list removal_list;
+       struct lv_list *lvl;
+
+       dm_list_init(&removal_list);
+
+       if (!_raid_extract_images(lv, new_count, pvs, 1,
+                                &removal_list, &removal_list)) {
+               log_error("Failed to extract images from %s/%s",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       /* Convert to linear? */
+       if (new_count == 1) {
+               if (!_raid_remove_top_layer(lv, &removal_list)) {
+                       log_error("Failed to remove RAID layer"
+                                 " after linear conversion");
+                       return 0;
+               }
+               lv->status &= ~LV_NOTSYNCED;
+       }
+
+       if (!vg_write(lv->vg)) {
+               log_error("Failed to write changes to %s in %s",
+                         lv->name, lv->vg->name);
+               return 0;
+       }
+
+       if (!suspend_lv(lv->vg->cmd, lv)) {
+               log_error("Failed to suspend %s/%s before committing changes",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       if (!vg_commit(lv->vg)) {
+               log_error("Failed to commit changes to %s in %s",
+                         lv->name, lv->vg->name);
+               return 0;
+       }
+
+       /*
+        * We resume the extracted sub-LVs first so they are renamed
+        * and won't conflict with the remaining (possibly shifted)
+        * sub-LVs.
+        */
+       dm_list_iterate_items(lvl, &removal_list) {
+               if (!resume_lv(lv->vg->cmd, lvl->lv)) {
+                       log_error("Failed to resume extracted LVs");
+                       return 0;
+               }
+       }
+
+       /*
+        * Resume the remaining LVs
+        * We must start by resuming the sub-LVs first (which would
+        * otherwise be handled automatically) because the shifting
+        * of positions could otherwise cause name collisions.  For
+        * example, if position 0 of a 3-way array is removed, position
+        * 1 and 2 must be shifted and renamed 0 and 1.  If position 2
+        * tries to rename first, it will collide with the existing
+        * position 1.
+        */
+       if (!_bottom_up_resume(lv)) {
+               log_error("Failed to resume %s/%s after committing changes",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       /*
+        * Eliminate the extracted LVs
+        */
+       sync_local_dev_names(lv->vg->cmd);
+       if (!dm_list_empty(&removal_list)) {
+               dm_list_iterate_items(lvl, &removal_list) {
+                       if (!deactivate_lv(lv->vg->cmd, lvl->lv))
+                               return_0;
+                       if (!lv_remove(lvl->lv))
+                               return_0;
+               }
+
+               if (!vg_write(lv->vg) || !vg_commit(lv->vg))
+                       return_0;
+       }
+
+       return 1;
+}
+
+/*
+ * lv_raid_change_image_count
+ * @lv
+ * @new_count: The absolute count of images (e.g. '2' for a 2-way mirror)
+ * @pvs: The list of PVs that are candidates for removal (or empty list)
+ *
+ * RAID arrays have 'images' which are composed of two parts, they are:
+ *    - 'rimage': The data/parity holding portion
+ *    - 'rmeta' : The metadata holding portion (i.e. superblock/bitmap area)
+ * This function adds or removes _both_ portions of the image and commits
+ * the results.
+ *
+ * Returns: 1 on success, 0 on failure
+ */
+int lv_raid_change_image_count(struct logical_volume *lv,
+                              uint32_t new_count, struct dm_list *pvs)
+{
+       uint32_t old_count = lv_raid_image_count(lv);
+
+       if (old_count == new_count) {
+               log_error("%s/%s already has image count of %d",
+                         lv->vg->name, lv->name, new_count);
+               return 1;
+       }
+
+       if (old_count > new_count)
+               return _raid_remove_images(lv, new_count, pvs);
+
+       return _raid_add_images(lv, new_count, pvs);
+}
+
+int lv_raid_split(struct logical_volume *lv, const char *split_name,
+                 uint32_t new_count, struct dm_list *splittable_pvs)
+{
+       struct lv_list *lvl;
+       struct dm_list removal_list, data_list;
+       struct cmd_context *cmd = lv->vg->cmd;
+       uint32_t old_count = lv_raid_image_count(lv);
+       struct logical_volume *tracking;
+       struct dm_list tracking_pvs;
+
+       dm_list_init(&removal_list);
+       dm_list_init(&data_list);
+
+       if ((old_count - new_count) != 1) {
+               log_error("Unable to split more than one image from %s/%s",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       if (!seg_is_mirrored(first_seg(lv))) {
+               log_error("Unable to split logical volume of segment type, %s",
+                         first_seg(lv)->segtype->ops->name(first_seg(lv)));
+               return 0;
+       }
+
+       if (find_lv_in_vg(lv->vg, split_name)) {
+               log_error("Logical Volume \"%s\" already exists in %s",
+                         split_name, lv->vg->name);
+               return 0;
+       }
+
+       if (!_raid_in_sync(lv)) {
+               log_error("Unable to split %s/%s while it is not in-sync.",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       /*
+        * We only allow a split while there is tracking if it is to
+        * complete the split of the tracking sub-LV
+        */
+       if (_lv_is_raid_with_tracking(lv, &tracking)) {
+               if (!_lv_is_on_pvs(tracking, splittable_pvs)) {
+                       log_error("Unable to split additional image from %s "
+                                 "while tracking changes for %s",
+                                 lv->name, tracking->name);
+                       return 0;
+               } else {
+                       /* Ensure we only split the tracking image */
+                       dm_list_init(&tracking_pvs);
+                       splittable_pvs = &tracking_pvs;
+                       if (!_get_pv_list_for_lv(tracking, splittable_pvs))
+                               return_0;
+               }
+       }
+
+       if (!_raid_extract_images(lv, new_count, splittable_pvs, 1,
+                                &removal_list, &data_list)) {
+               log_error("Failed to extract images from %s/%s",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       /* Convert to linear? */
+       if ((new_count == 1) && !_raid_remove_top_layer(lv, &removal_list)) {
+               log_error("Failed to remove RAID layer after linear conversion");
+               return 0;
+       }
+
+       /* Get first item */
+       dm_list_iterate_items(lvl, &data_list)
+               break;
+
+       lvl->lv->name = split_name;
+
+       if (!vg_write(lv->vg)) {
+               log_error("Failed to write changes to %s in %s",
+                         lv->name, lv->vg->name);
+               return 0;
+       }
+
+       if (!suspend_lv(cmd, lv)) {
+               log_error("Failed to suspend %s/%s before committing changes",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       if (!vg_commit(lv->vg)) {
+               log_error("Failed to commit changes to %s in %s",
+                         lv->name, lv->vg->name);
+               return 0;
+       }
+
+       /*
+        * First resume the newly split LV and LVs on the removal list.
+        * This is necessary so that there are no name collisions due to
+        * the original RAID LV having possibly had sub-LVs that have been
+        * shifted and renamed.
+        */
+       if (!resume_lv(cmd, lvl->lv))
+               return_0;
+       dm_list_iterate_items(lvl, &removal_list)
+               if (!resume_lv(cmd, lvl->lv))
+                       return_0;
+
+       /*
+        * Resume the remaining LVs
+        * We must start by resuming the sub-LVs first (which would
+        * otherwise be handled automatically) because the shifting
+        * of positions could otherwise cause name collisions.  For
+        * example, if position 0 of a 3-way array is split, position
+        * 1 and 2 must be shifted and renamed 0 and 1.  If position 2
+        * tries to rename first, it will collide with the existing
+        * position 1.
+        */
+       if (!_bottom_up_resume(lv)) {
+               log_error("Failed to resume %s/%s after committing changes",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       /*
+        * Eliminate the residual LVs
+        */
+       dm_list_iterate_items(lvl, &removal_list) {
+               if (!deactivate_lv(cmd, lvl->lv))
+                       return_0;
+
+               if (!lv_remove(lvl->lv))
+                       return_0;
+       }
+
+       if (!vg_write(lv->vg) || !vg_commit(lv->vg))
+               return_0;
+
+       return 1;
+}
+
+/*
+ * lv_raid_split_and_track
+ * @lv
+ * @splittable_pvs
+ *
+ * Only allows a single image to be split while tracking.  The image
+ * never actually leaves the mirror.  It is simply made visible.  This
+ * action triggers two things: 1) users are able to access the (data) image
+ * and 2) lower layers replace images marked with a visible flag with
+ * error targets.
+ *
+ * Returns: 1 on success, 0 on error
+ */
+int lv_raid_split_and_track(struct logical_volume *lv,
+                           struct dm_list *splittable_pvs)
+{
+       int s;
+       struct lv_segment *seg = first_seg(lv);
+
+       if (!seg_is_mirrored(seg)) {
+               log_error("Unable to split images from non-mirrored RAID");
+               return 0;
+       }
+
+       if (!_raid_in_sync(lv)) {
+               log_error("Unable to split image from %s/%s while not in-sync",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       /* Cannot track two split images at once */
+       if (lv_is_raid_with_tracking(lv)) {
+               log_error("Cannot track more than one split image at a time");
+               return 0;
+       }
+
+       for (s = seg->area_count - 1; s >= 0; s--) {
+               if (!_lv_is_on_pvs(seg_lv(seg, s), splittable_pvs))
+                       continue;
+               lv_set_visible(seg_lv(seg, s));
+               seg_lv(seg, s)->status &= ~LVM_WRITE;
+               break;
+       }
+
+       if (s >= (int) seg->area_count) {
+               log_error("Unable to find image to satisfy request");
+               return 0;
+       }
+
+       if (!vg_write(lv->vg)) {
+               log_error("Failed to write changes to %s in %s",
+                         lv->name, lv->vg->name);
+               return 0;
+       }
+
+       if (!suspend_lv(lv->vg->cmd, lv)) {
+               log_error("Failed to suspend %s/%s before committing changes",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       if (!vg_commit(lv->vg)) {
+               log_error("Failed to commit changes to %s in %s",
+                         lv->name, lv->vg->name);
+               return 0;
+       }
+
+       log_print_unless_silent("%s split from %s for read-only purposes.",
+                               seg_lv(seg, s)->name, lv->name);
+
+       /* Resume original LV */
+       if (!resume_lv(lv->vg->cmd, lv)) {
+               log_error("Failed to resume %s/%s after committing changes",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       /* Activate the split (and tracking) LV */
+       if (!_activate_sublv_preserving_excl(lv, seg_lv(seg, s)))
+               return 0;
+
+       log_print_unless_silent("Use 'lvconvert --merge %s/%s' to merge back into %s",
+                               lv->vg->name, seg_lv(seg, s)->name, lv->name);
+       return 1;
+}
+
+int lv_raid_merge(struct logical_volume *image_lv)
+{
+       uint32_t s;
+       char *p, *lv_name;
+       struct lv_list *lvl;
+       struct logical_volume *lv;
+       struct logical_volume *meta_lv = NULL;
+       struct lv_segment *seg;
+       struct volume_group *vg = image_lv->vg;
+
+       lv_name = dm_pool_strdup(vg->vgmem, image_lv->name);
+       if (!lv_name)
+               return_0;
+
+       if (!(p = strstr(lv_name, "_rimage_"))) {
+               log_error("Unable to merge non-mirror image %s/%s",
+                         vg->name, image_lv->name);
+               return 0;
+       }
+       *p = '\0'; /* lv_name is now that of top-level RAID */
+
+       if (image_lv->status & LVM_WRITE) {
+               log_error("%s/%s is not read-only - refusing to merge",
+                         vg->name, image_lv->name);
+               return 0;
+       }
+
+       if (!(lvl = find_lv_in_vg(vg, lv_name))) {
+               log_error("Unable to find containing RAID array for %s/%s",
+                         vg->name, image_lv->name);
+               return 0;
+       }
+       lv = lvl->lv;
+       seg = first_seg(lv);
+       for (s = 0; s < seg->area_count; s++) {
+               if (seg_lv(seg, s) == image_lv) {
+                       meta_lv = seg_metalv(seg, s);
+               }
+       }
+       if (!meta_lv)
+               return_0;
+
+       if (!deactivate_lv(vg->cmd, meta_lv)) {
+               log_error("Failed to deactivate %s", meta_lv->name);
+               return 0;
+       }
+
+       if (!deactivate_lv(vg->cmd, image_lv)) {
+               log_error("Failed to deactivate %s/%s before merging",
+                         vg->name, image_lv->name);
+               return 0;
+       }
+       lv_set_hidden(image_lv);
+       image_lv->status |= (lv->status & LVM_WRITE);
+       image_lv->status |= RAID_IMAGE;
+
+       if (!vg_write(vg)) {
+               log_error("Failed to write changes to %s in %s",
+                         lv->name, vg->name);
+               return 0;
+       }
+
+       if (!suspend_lv(vg->cmd, lv)) {
+               log_error("Failed to suspend %s/%s before committing changes",
+                         vg->name, lv->name);
+               return 0;
+       }
+
+       if (!vg_commit(vg)) {
+               log_error("Failed to commit changes to %s in %s",
+                         lv->name, vg->name);
+               return 0;
+       }
+
+       if (!resume_lv(vg->cmd, lv)) {
+               log_error("Failed to resume %s/%s after committing changes",
+                         vg->name, lv->name);
+               return 0;
+       }
+
+       log_print_unless_silent("%s/%s successfully merged back into %s/%s",
+                               vg->name, image_lv->name, vg->name, lv->name);
+       return 1;
+}
+
+static int _convert_mirror_to_raid1(struct logical_volume *lv,
+                                   const struct segment_type *new_segtype)
+{
+       uint32_t s;
+       struct lv_segment *seg = first_seg(lv);
+       struct lv_list lvl_array[seg->area_count], *lvl;
+       struct dm_list meta_lvs;
+       struct lv_segment_area *meta_areas;
+
+       dm_list_init(&meta_lvs);
+
+       if (!_raid_in_sync(lv)) {
+               log_error("Unable to convert %s/%s while it is not in-sync",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       meta_areas = dm_pool_zalloc(lv->vg->vgmem,
+                                   lv_mirror_count(lv) * sizeof(*meta_areas));
+       if (!meta_areas) {
+               log_error("Failed to allocate memory");
+               return 0;
+       }
+
+       for (s = 0; s < seg->area_count; s++) {
+               log_debug("Allocating new metadata LV for %s",
+                         seg_lv(seg, s)->name);
+               if (!_alloc_rmeta_for_lv(seg_lv(seg, s), &(lvl_array[s].lv))) {
+                       log_error("Failed to allocate metadata LV for %s in %s",
+                                 seg_lv(seg, s)->name, lv->name);
+                       return 0;
+               }
+               dm_list_add(&meta_lvs, &(lvl_array[s].list));
+       }
+
+       log_debug("Clearing newly allocated metadata LVs");
+       if (!_clear_lvs(&meta_lvs)) {
+               log_error("Failed to initialize metadata LVs");
+               return 0;
+       }
+
+       if (seg->log_lv) {
+               log_debug("Removing mirror log, %s", seg->log_lv->name);
+               if (!remove_mirror_log(lv->vg->cmd, lv, NULL, 0)) {
+                       log_error("Failed to remove mirror log");
+                       return 0;
+               }
+       }
+
+       seg->meta_areas = meta_areas;
+       s = 0;
+
+       dm_list_iterate_items(lvl, &meta_lvs) {
+               log_debug("Adding %s to %s", lvl->lv->name, lv->name);
+
+               /* Images are known to be in-sync */
+               lvl->lv->status &= ~LV_REBUILD;
+               first_seg(lvl->lv)->status &= ~LV_REBUILD;
+               lv_set_hidden(lvl->lv);
+
+               if (!set_lv_segment_area_lv(seg, s, lvl->lv, 0,
+                                           lvl->lv->status)) {
+                       log_error("Failed to add %s to %s",
+                                 lvl->lv->name, lv->name);
+                       return 0;
+               }
+               s++;
+       }
+
+       for (s = 0; s < seg->area_count; s++) {
+               char *new_name;
+
+               new_name = dm_pool_zalloc(lv->vg->vgmem,
+                                         strlen(lv->name) +
+                                         strlen("_rimage_XXn"));
+               if (!new_name) {
+                       log_error("Failed to rename mirror images");
+                       return 0;
+               }
+
+               sprintf(new_name, "%s_rimage_%u", lv->name, s);
+               log_debug("Renaming %s to %s", seg_lv(seg, s)->name, new_name);
+               seg_lv(seg, s)->name = new_name;
+               seg_lv(seg, s)->status &= ~MIRROR_IMAGE;
+               seg_lv(seg, s)->status |= RAID_IMAGE;
+       }
+       init_mirror_in_sync(1);
+
+       log_debug("Setting new segtype for %s", lv->name);
+       seg->segtype = new_segtype;
+       lv->status &= ~MIRRORED;
+       lv->status |= RAID;
+       seg->status |= RAID;
+
+       if (!vg_write(lv->vg)) {
+               log_error("Failed to write changes to %s in %s",
+                         lv->name, lv->vg->name);
+               return 0;
+       }
+
+       if (!suspend_lv(lv->vg->cmd, lv)) {
+               log_error("Failed to suspend %s/%s before committing changes",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       if (!vg_commit(lv->vg)) {
+               log_error("Failed to commit changes to %s in %s",
+                         lv->name, lv->vg->name);
+               return 0;
+       }
+
+       if (!resume_lv(lv->vg->cmd, lv)) {
+               log_error("Failed to resume %s/%s after committing changes",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * lv_raid_reshape
+ * @lv
+ * @new_segtype
+ *
+ * Convert an LV from one RAID type (or 'mirror' segtype) to another.
+ *
+ * Returns: 1 on success, 0 on failure
+ */
+int lv_raid_reshape(struct logical_volume *lv,
+                   const struct segment_type *new_segtype)
+{
+       struct lv_segment *seg = first_seg(lv);
+
+       if (!new_segtype) {
+               log_error(INTERNAL_ERROR "New segtype not specified");
+               return 0;
+       }
+
+       if (!strcmp(seg->segtype->name, "mirror") &&
+           (!strcmp(new_segtype->name, "raid1")))
+           return _convert_mirror_to_raid1(lv, new_segtype);
+
+       log_error("Converting the segment type for %s/%s from %s to %s"
+                 " is not yet supported.", lv->vg->name, lv->name,
+                 seg->segtype->ops->name(seg), new_segtype->name);
+       return 0;
+}
+
+/*
+ * lv_raid_replace
+ * @lv
+ * @replace_pvs
+ * @allocatable_pvs
+ *
+ * Replace the specified PVs.
+ */
+int lv_raid_replace(struct logical_volume *lv,
+                   struct dm_list *remove_pvs,
+                   struct dm_list *allocate_pvs)
+{
+       uint32_t s, sd, match_count = 0;
+       struct dm_list old_meta_lvs, old_data_lvs;
+       struct dm_list new_meta_lvs, new_data_lvs;
+       struct lv_segment *raid_seg = first_seg(lv);
+       struct lv_list *lvl;
+       char *tmp_names[raid_seg->area_count * 2];
+
+       dm_list_init(&old_meta_lvs);
+       dm_list_init(&old_data_lvs);
+       dm_list_init(&new_meta_lvs);
+       dm_list_init(&new_data_lvs);
+
+       /*
+        * How many sub-LVs are being removed?
+        */
+       for (s = 0; s < raid_seg->area_count; s++) {
+               if ((seg_type(raid_seg, s) == AREA_UNASSIGNED) ||
+                   (seg_metatype(raid_seg, s) == AREA_UNASSIGNED)) {
+                       log_error("Unable to replace RAID images while the "
+                                 "array has unassigned areas");
+                       return 0;
+               }
+
+               if (_lv_is_on_pvs(seg_lv(raid_seg, s), remove_pvs) ||
+                   _lv_is_on_pvs(seg_metalv(raid_seg, s), remove_pvs))
+                       match_count++;
+       }
+
+       if (!match_count) {
+               log_verbose("%s/%s does not contain devices specified"
+                           " for replacement", lv->vg->name, lv->name);
+               return 1;
+       } else if (match_count == raid_seg->area_count) {
+               log_error("Unable to remove all PVs from %s/%s at once.",
+                         lv->vg->name, lv->name);
+               return 0;
+       } else if (raid_seg->segtype->parity_devs &&
+                  (match_count > raid_seg->segtype->parity_devs)) {
+               log_error("Unable to replace more than %u PVs from (%s) %s/%s",
+                         raid_seg->segtype->parity_devs,
+                         raid_seg->segtype->ops->name(raid_seg),
+                         lv->vg->name, lv->name);
+               return 0;
+       } else if (!strcmp(raid_seg->segtype->name, "raid10")) {
+               uint32_t i, rebuilds_per_group = 0;
+               /* FIXME: We only support 2-way mirrors in RAID10 currently */
+               uint32_t copies = 2;
+
+               for (i = 0; i < raid_seg->area_count * copies; i++) {
+                       s = i % raid_seg->area_count;
+                       if (!(i % copies))
+                               rebuilds_per_group = 0;
+                       if (_lv_is_on_pvs(seg_lv(raid_seg, s), remove_pvs) ||
+                           _lv_is_on_pvs(seg_metalv(raid_seg, s), remove_pvs))
+                               rebuilds_per_group++;
+                       if (rebuilds_per_group >= copies) {
+                               log_error("Unable to replace all the devices "
+                                         "in a RAID10 mirror group.");
+                               return 0;
+                       }
+               }
+       }
+
+       /*
+        * Allocate the new image components first
+        * - This makes it easy to avoid all currently used devs
+        * - We can immediately tell if there is enough space
+        *
+        * - We need to change the LV names when we insert them.
+        */
+try_again:
+       if (!_alloc_image_components(lv, allocate_pvs, match_count,
+                                    &new_meta_lvs, &new_data_lvs)) {
+               log_error("Failed to allocate replacement images for %s/%s",
+                         lv->vg->name, lv->name);
+
+               /*
+                * If this is a repair, then try to
+                * do better than all-or-nothing
+                */
+               if (match_count > 1) {
+                       log_error("Attempting replacement of %u devices"
+                                 " instead of %u", match_count - 1, match_count);
+                       match_count--;
+
+                       /*
+                        * Since we are replacing some but not all of the bad
+                        * devices, we must set partial_activation
+                        */
+                       lv->vg->cmd->partial_activation = 1;
+                       goto try_again;
+               }
+               return 0;
+       }
+
+       /*
+        * Remove the old images
+        * - If we did this before the allocate, we wouldn't have to rename
+        *   the allocated images, but it'd be much harder to avoid the right
+        *   PVs during allocation.
+        */
+       if (!_raid_extract_images(lv, raid_seg->area_count - match_count,
+                                 remove_pvs, 0,
+                                 &old_meta_lvs, &old_data_lvs)) {
+               log_error("Failed to remove the specified images from %s/%s",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       /*
+        * Skip metadata operation normally done to clear the metadata sub-LVs.
+        *
+        * The LV_REBUILD flag is set on the new sub-LVs,
+        * so they will be rebuilt and we don't need to clear the metadata dev.
+        */
+
+       for (s = 0; s < raid_seg->area_count; s++) {
+               tmp_names[s] = NULL;
+               sd = s + raid_seg->area_count;
+               tmp_names[sd] = NULL;
+
+               if ((seg_type(raid_seg, s) == AREA_UNASSIGNED) &&
+                   (seg_metatype(raid_seg, s) == AREA_UNASSIGNED)) {
+                       /* Adjust the new metadata LV name */
+                       lvl = dm_list_item(dm_list_first(&new_meta_lvs),
+                                          struct lv_list);
+                       dm_list_del(&lvl->list);
+                       tmp_names[s] = dm_pool_alloc(lv->vg->vgmem,
+                                                   strlen(lvl->lv->name) + 1);
+                       if (!tmp_names[s])
+                               return_0;
+                       if (dm_snprintf(tmp_names[s], strlen(lvl->lv->name) + 1,
+                                       "%s_rmeta_%u", lv->name, s) < 0)
+                               return_0;
+                       if (!set_lv_segment_area_lv(raid_seg, s, lvl->lv, 0,
+                                                   lvl->lv->status)) {
+                               log_error("Failed to add %s to %s",
+                                         lvl->lv->name, lv->name);
+                               return 0;
+                       }
+                       lv_set_hidden(lvl->lv);
+
+                       /* Adjust the new data LV name */
+                       lvl = dm_list_item(dm_list_first(&new_data_lvs),
+                                          struct lv_list);
+                       dm_list_del(&lvl->list);
+                       tmp_names[sd] = dm_pool_alloc(lv->vg->vgmem,
+                                                    strlen(lvl->lv->name) + 1);
+                       if (!tmp_names[sd])
+                               return_0;
+                       if (dm_snprintf(tmp_names[sd], strlen(lvl->lv->name) + 1,
+                                       "%s_rimage_%u", lv->name, s) < 0)
+                               return_0;
+                       if (!set_lv_segment_area_lv(raid_seg, s, lvl->lv, 0,
+                                                   lvl->lv->status)) {
+                               log_error("Failed to add %s to %s",
+                                         lvl->lv->name, lv->name);
+                               return 0;
+                       }
+                       lv_set_hidden(lvl->lv);
+               }
+       }
+
+       if (!vg_write(lv->vg)) {
+               log_error("Failed to write changes to %s in %s",
+                         lv->name, lv->vg->name);
+               return 0;
+       }
+
+       if (!suspend_lv_origin(lv->vg->cmd, lv)) {
+               log_error("Failed to suspend %s/%s before committing changes",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       if (!vg_commit(lv->vg)) {
+               log_error("Failed to commit changes to %s in %s",
+                         lv->name, lv->vg->name);
+               return 0;
+       }
+
+       if (!resume_lv_origin(lv->vg->cmd, lv)) {
+               log_error("Failed to resume %s/%s after committing changes",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       dm_list_iterate_items(lvl, &old_meta_lvs) {
+               if (!deactivate_lv(lv->vg->cmd, lvl->lv))
+                       return_0;
+               if (!lv_remove(lvl->lv))
+                       return_0;
+       }
+       dm_list_iterate_items(lvl, &old_data_lvs) {
+               if (!deactivate_lv(lv->vg->cmd, lvl->lv))
+                       return_0;
+               if (!lv_remove(lvl->lv))
+                       return_0;
+       }
+
+       /* Update new sub-LVs to correct name and clear REBUILD flag */
+       for (s = 0; s < raid_seg->area_count; s++) {
+               sd = s + raid_seg->area_count;
+               if (tmp_names[s] && tmp_names[sd]) {
+                       seg_metalv(raid_seg, s)->name = tmp_names[s];
+                       seg_lv(raid_seg, s)->name = tmp_names[sd];
+                       seg_metalv(raid_seg, s)->status &= ~LV_REBUILD;
+                       seg_lv(raid_seg, s)->status &= ~LV_REBUILD;
+               }
+       }
+
+       if (!vg_write(lv->vg)) {
+               log_error("Failed to write changes to %s in %s",
+                         lv->name, lv->vg->name);
+               return 0;
+       }
+
+       if (!suspend_lv_origin(lv->vg->cmd, lv)) {
+               log_error("Failed to suspend %s/%s before committing changes",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       if (!vg_commit(lv->vg)) {
+               log_error("Failed to commit changes to %s in %s",
+                         lv->name, lv->vg->name);
+               return 0;
+       }
+
+       if (!resume_lv_origin(lv->vg->cmd, lv)) {
+               log_error("Failed to resume %s/%s after committing changes",
+                         lv->vg->name, lv->name);
+               return 0;
+       }
+
+       return 1;
+}
index 79abca04f2911b5e779125d65dc3cd6e47154fe5..2853e50df65b9f99ef433585539fe7fc0661bc6d 100644 (file)
@@ -445,14 +445,6 @@ int lv_is_rimage(const struct logical_volume *lv)
        return (lv->rdevice && lv->rdevice->lv == lv);
 }
 
-/**
- * Is this LV rlog
- */
-int lv_is_rlog(const struct logical_volume *lv)
-{
-       return (lv->status & REPLICATOR_LOG);
-}
-
 /**
  * Is this LV sync log
  */
@@ -597,9 +589,9 @@ void free_cmd_vgs(struct dm_list *cmd_vgs)
        /* Backward iterate cmd_vg list */
        dm_list_iterate_back_items(cvl, cmd_vgs) {
                if (vg_read_error(cvl->vg))
-                       free_vg(cvl->vg);
+                       release_vg(cvl->vg);
                else
-                       unlock_and_free_vg(cvl->vg->cmd, cvl->vg, cvl->vg_name);
+                       unlock_and_release_vg(cvl->vg->cmd, cvl->vg, cvl->vg_name);
                cvl->vg = NULL;
        }
 }
@@ -687,7 +679,7 @@ void lv_release_replicator_vgs(struct logical_volume *lv)
 
        dm_list_iterate_back_items(rsite, &first_seg(lv)->replicator->rsites)
                if (rsite->vg_name && rsite->vg) {
-                       free_vg(rsite->vg);
+                       release_vg(rsite->vg);
                        rsite->vg = NULL;
                }
 }
index 6d50746b2e4b92b13dfa528b5c1896f0e22f4899..d3ad2b2526526cc74ca5df3bb6e46c596a489246 100644 (file)
 
 struct segtype_handler;
 struct cmd_context;
-struct config_tree;
+struct dm_config_tree;
 struct lv_segment;
+struct lv_activate_opts;
 struct formatter;
-struct config_node;
+struct dm_config_node;
 struct dev_manager;
 
 /* Feature flags */
@@ -37,14 +38,22 @@ struct dev_manager;
 #define SEG_MONITORED          0x00000080U
 #define SEG_REPLICATOR         0x00000100U
 #define SEG_REPLICATOR_DEV     0x00000200U
+#define SEG_RAID               0x00000400U
+#define SEG_THIN_POOL          0x00000800U
+#define SEG_THIN_VOLUME                0x00001000U
 #define SEG_UNKNOWN            0x80000000U
 
 #define seg_is_mirrored(seg)   ((seg)->segtype->flags & SEG_AREAS_MIRRORED ? 1 : 0)
 #define seg_is_replicator(seg) ((seg)->segtype->flags & SEG_REPLICATOR ? 1 : 0)
 #define seg_is_replicator_dev(seg) ((seg)->segtype->flags & SEG_REPLICATOR_DEV ? 1 : 0)
 #define seg_is_striped(seg)    ((seg)->segtype->flags & SEG_AREAS_STRIPED ? 1 : 0)
+#define     seg_is_linear(seg)  (seg_is_striped(seg) && ((seg)->area_count == 1))
 #define seg_is_snapshot(seg)   ((seg)->segtype->flags & SEG_SNAPSHOT ? 1 : 0)
 #define seg_is_virtual(seg)    ((seg)->segtype->flags & SEG_VIRTUAL ? 1 : 0)
+#define seg_is_raid(seg)       ((seg)->segtype->flags & SEG_RAID ? 1 : 0)
+#define seg_is_thin(seg)       ((seg)->segtype->flags & (SEG_THIN_POOL|SEG_THIN_VOLUME) ? 1 : 0)
+#define seg_is_thin_pool(seg)  ((seg)->segtype->flags & SEG_THIN_POOL ? 1 : 0)
+#define seg_is_thin_volume(seg)        ((seg)->segtype->flags & SEG_THIN_VOLUME ? 1 : 0)
 #define seg_can_split(seg)     ((seg)->segtype->flags & SEG_CAN_SPLIT ? 1 : 0)
 #define seg_cannot_be_zeroed(seg) ((seg)->segtype->flags & SEG_CANNOT_BE_ZEROED ? 1 : 0)
 #define seg_monitored(seg)     ((seg)->segtype->flags & SEG_MONITORED ? 1 : 0)
@@ -52,36 +61,46 @@ struct dev_manager;
 
 #define segtype_is_striped(segtype)    ((segtype)->flags & SEG_AREAS_STRIPED ? 1 : 0)
 #define segtype_is_mirrored(segtype)   ((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0)
+#define segtype_is_raid(segtype)       ((segtype)->flags & SEG_RAID ? 1 : 0)
+#define segtype_is_thin(segtype)       ((segtype)->flags & (SEG_THIN_POOL|SEG_THIN_VOLUME) ? 1 : 0)
+#define segtype_is_thin_pool(segtype)  ((segtype)->flags & SEG_THIN_POOL ? 1 : 0)
+#define segtype_is_thin_volume(segtype)        ((segtype)->flags & SEG_THIN_VOLUME ? 1 : 0)
 #define segtype_is_virtual(segtype)    ((segtype)->flags & SEG_VIRTUAL ? 1 : 0)
 
 struct segment_type {
        struct dm_list list;            /* Internal */
        struct cmd_context *cmd;        /* lvm_register_segtype() sets this. */
+
        uint32_t flags;
+       uint32_t parity_devs;           /* Parity drives required by segtype */
+
        struct segtype_handler *ops;
        const char *name;
+
        void *library;                  /* lvm_register_segtype() sets this. */
        void *private;                  /* For the segtype handler to use. */
 };
 
 struct segtype_handler {
        const char *(*name) (const struct lv_segment * seg);
-       const char *(*target_name) (const struct lv_segment * seg);
+       const char *(*target_name) (const struct lv_segment *seg,
+                                   const struct lv_activate_opts *laopts);
        void (*display) (const struct lv_segment * seg);
        int (*text_export) (const struct lv_segment * seg,
                            struct formatter * f);
-       int (*text_import_area_count) (const struct config_node * sn,
+       int (*text_import_area_count) (const struct dm_config_node * sn,
                                       uint32_t *area_count);
        int (*text_import) (struct lv_segment * seg,
-                           const struct config_node * sn,
+                           const struct dm_config_node * sn,
                            struct dm_hash_table * pv_hash);
        int (*merge_segments) (struct lv_segment * seg1,
                               struct lv_segment * seg2);
        int (*add_target_line) (struct dev_manager *dm, struct dm_pool *mem,
-                                struct cmd_context *cmd, void **target_state,
-                                struct lv_segment *seg,
-                                struct dm_tree_node *node, uint64_t len,
-                                uint32_t *pvmove_mirror_count);
+                               struct cmd_context *cmd, void **target_state,
+                               struct lv_segment *seg,
+                               const struct lv_activate_opts *laopts,
+                               struct dm_tree_node *node, uint64_t len,
+                               uint32_t *pvmove_mirror_count);
        int (*target_status_compatible) (const char *type);
        int (*check_transient_status) (struct lv_segment *seg, char *params);
        int (*target_percent) (void **target_state,
@@ -114,10 +133,18 @@ struct segment_type *init_striped_segtype(struct cmd_context *cmd);
 struct segment_type *init_zero_segtype(struct cmd_context *cmd);
 struct segment_type *init_error_segtype(struct cmd_context *cmd);
 struct segment_type *init_free_segtype(struct cmd_context *cmd);
-struct segment_type *init_unknown_segtype(struct cmd_context *cmd, const char *name);
+struct segment_type *init_unknown_segtype(struct cmd_context *cmd,
+                                         const char *name);
+#ifdef RAID_INTERNAL
+int init_raid_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
+#endif
 
 #ifdef REPLICATOR_INTERNAL
-int init_replicator_segtype(struct segtype_library *seglib);
+int init_replicator_segtype(struct cmd_context *cmd, struct segtype_library *seglib);
+#endif
+
+#ifdef THIN_INTERNAL
+int init_thin_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
 #endif
 
 #ifdef SNAPSHOT_INTERNAL
index cb5df6b45e9fde4a6297596762337aefc1f63f9a..5766d0b1460995e35c4556788d23b2424567c568 100644 (file)
@@ -81,7 +81,9 @@ struct lv_segment *find_cow(const struct logical_volume *lv)
 /* Given a cow LV, return its origin */
 struct logical_volume *origin_from_cow(const struct logical_volume *lv)
 {
-       return lv->snapshot->origin;
+       if (lv->snapshot)
+               return lv->snapshot->origin;
+       return NULL;
 }
 
 void init_snapshot_seg(struct lv_segment *seg, struct logical_volume *origin,
@@ -172,7 +174,7 @@ int vg_add_snapshot(struct logical_volume *origin,
 
 int vg_remove_snapshot(struct logical_volume *cow)
 {
-       int preload_origin = 0;
+       int merging_snapshot = 0;
        struct logical_volume *origin = origin_from_cow(cow);
 
        dm_list_del(&cow->snapshot->origin_list);
@@ -193,7 +195,7 @@ int vg_remove_snapshot(struct logical_volume *cow)
                         *   when transitioning from "snapshot-merge" to
                         *   "snapshot-origin after a merge completes.
                         */
-                       preload_origin = 1;
+                       merging_snapshot = 1;
                }
        }
 
@@ -206,20 +208,26 @@ int vg_remove_snapshot(struct logical_volume *cow)
        cow->snapshot = NULL;
        lv_set_visible(cow);
 
-       if (preload_origin) {
-               if (!vg_write(origin->vg))
-                       return_0;
-               if (!suspend_lv(origin->vg->cmd, origin)) {
-                       log_error("Failed to refresh %s without snapshot.",
-                                 origin->name);
-                       return 0;
-               }
-               if (!vg_commit(origin->vg))
-                       return_0;
-               if (!resume_lv(origin->vg->cmd, origin)) {
-                       log_error("Failed to resume %s.", origin->name);
-                       return 0;
-               }
+       /* format1 must do the change in one step, with the commit last. */
+       if (!(origin->vg->fid->fmt->features & FMT_MDAS))
+               return 1;
+
+       if (!vg_write(origin->vg))
+               return_0;
+       if (!suspend_lv(origin->vg->cmd, origin)) {
+               log_error("Failed to refresh %s without snapshot.",
+                         origin->name);
+               return 0;
+       }
+       if (!vg_commit(origin->vg))
+               return_0;
+       if (!merging_snapshot && !resume_lv(origin->vg->cmd, cow)) {
+               log_error("Failed to resume %s.", cow->name);
+               return 0;
+       }
+       if (!resume_lv(origin->vg->cmd, origin)) {
+               log_error("Failed to resume %s.", origin->name);
+               return 0;
        }
 
        return 1;
diff --git a/lib/metadata/thin_manip.c b/lib/metadata/thin_manip.c
new file mode 100644 (file)
index 0000000..e7e96df
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "lib.h"
+#include "activate.h"
+#include "locking.h"
+#include "metadata.h"
+#include "segtype.h"
+#include "lv_alloc.h"
+#include "archiver.h"
+#include "defaults.h"
+
+int attach_pool_metadata_lv(struct lv_segment *pool_seg, struct logical_volume *metadata_lv)
+{
+       pool_seg->metadata_lv = metadata_lv;
+       metadata_lv->status |= THIN_POOL_METADATA;
+       lv_set_hidden(metadata_lv);
+
+       return add_seg_to_segs_using_this_lv(metadata_lv, pool_seg);
+}
+
+int attach_pool_data_lv(struct lv_segment *pool_seg, struct logical_volume *pool_data_lv)
+{
+       if (!set_lv_segment_area_lv(pool_seg, 0, pool_data_lv, 0, THIN_POOL_DATA))
+               return_0;
+
+       lv_set_hidden(pool_data_lv);
+
+       return 1;
+}
+
+int attach_pool_lv(struct lv_segment *seg, struct logical_volume *pool_lv,
+                  struct logical_volume *origin)
+{
+       seg->pool_lv = pool_lv;
+       seg->lv->status |= THIN_VOLUME;
+       seg->origin = origin;
+
+       if (origin && !add_seg_to_segs_using_this_lv(origin, seg))
+               return_0;
+
+       return add_seg_to_segs_using_this_lv(pool_lv, seg);
+}
+
+int detach_pool_lv(struct lv_segment *seg)
+{
+       struct lv_thin_message *tmsg, *tmp;
+       struct seg_list *sl, *tsl;
+       int no_update = 0;
+
+       if (!seg->pool_lv || !lv_is_thin_pool(seg->pool_lv)) {
+               log_error(INTERNAL_ERROR "LV %s is not a thin volume",
+                         seg->lv->name);
+               return 0;
+       }
+
+       /* Drop any message referencing removed segment */
+       dm_list_iterate_items_safe(tmsg, tmp, &(first_seg(seg->pool_lv)->thin_messages)) {
+               switch (tmsg->type) {
+               case DM_THIN_MESSAGE_CREATE_SNAP:
+               case DM_THIN_MESSAGE_CREATE_THIN:
+                       if (tmsg->u.lv == seg->lv) {
+                               log_debug("Discarding message for LV %s.",
+                                         tmsg->u.lv->name);
+                               dm_list_del(&tmsg->list);
+                               no_update = 1; /* Replacing existing */
+                       }
+                       break;
+               case DM_THIN_MESSAGE_DELETE:
+                       if (tmsg->u.delete_id == seg->device_id) {
+                               log_error(INTERNAL_ERROR "Trying to delete %u again.",
+                                         tmsg->u.delete_id);
+                               return 0;
+                       }
+                       break;
+               default:
+                       log_error(INTERNAL_ERROR "Unsupported message type %u.", tmsg->type);
+                       break;
+               }
+       }
+
+       if (!attach_pool_message(first_seg(seg->pool_lv),
+                                DM_THIN_MESSAGE_DELETE,
+                                NULL, seg->device_id, no_update))
+               return_0;
+
+       if (!remove_seg_from_segs_using_this_lv(seg->pool_lv, seg))
+               return_0;
+
+       if (seg->origin &&
+           !remove_seg_from_segs_using_this_lv(seg->origin, seg))
+               return_0;
+
+       /* If thin origin, remove it from related thin snapshots */
+       /*
+        * TODO: map removal of origin as snapshot lvconvert --merge?
+        * i.e. rename thin snapshot to origin thin origin
+        */
+       dm_list_iterate_items_safe(sl, tsl, &seg->lv->segs_using_this_lv) {
+               if (!seg_is_thin_volume(sl->seg) ||
+                   (seg->lv != sl->seg->origin))
+                       continue;
+
+               if (!remove_seg_from_segs_using_this_lv(seg->lv, sl->seg))
+                       return_0;
+               /* Thin snapshot is now regular thin volume */
+               sl->seg->origin = NULL;
+       }
+
+       return 1;
+}
+
+int attach_pool_message(struct lv_segment *pool_seg, dm_thin_message_t type,
+                       struct logical_volume *lv, uint32_t delete_id,
+                       int no_update)
+{
+       struct lv_thin_message *tmsg;
+
+       if (!seg_is_thin_pool(pool_seg)) {
+               log_error(INTERNAL_ERROR "LV %s is not pool.", pool_seg->lv->name);
+               return 0;
+       }
+
+       if (pool_has_message(pool_seg, lv, delete_id)) {
+               if (lv)
+                       log_error("Message referring LV %s already queued in pool %s.",
+                                 lv->name, pool_seg->lv->name);
+               else
+                       log_error("Delete for device %u already queued in pool %s.",
+                                 delete_id, pool_seg->lv->name);
+               return 0;
+       }
+
+       if (!(tmsg = dm_pool_alloc(pool_seg->lv->vg->vgmem, sizeof(*tmsg)))) {
+               log_error("Failed to allocate memory for message.");
+               return 0;
+       }
+
+       switch (type) {
+       case DM_THIN_MESSAGE_CREATE_SNAP:
+       case DM_THIN_MESSAGE_CREATE_THIN:
+               tmsg->u.lv = lv;
+               break;
+       case DM_THIN_MESSAGE_DELETE:
+               tmsg->u.delete_id = delete_id;
+               break;
+       default:
+               log_error(INTERNAL_ERROR "Unsupported message type %u.", type);
+               return 0;
+       }
+
+       tmsg->type = type;
+
+       /* If the 1st message is add in non-read-only mode, modify transaction_id */
+       if (!no_update && dm_list_empty(&pool_seg->thin_messages))
+               pool_seg->transaction_id++;
+
+       dm_list_add(&pool_seg->thin_messages, &tmsg->list);
+
+       log_debug("Added %s message",
+                 (type == DM_THIN_MESSAGE_CREATE_SNAP ||
+                  type == DM_THIN_MESSAGE_CREATE_THIN) ? "create" :
+                 (type == DM_THIN_MESSAGE_DELETE) ? "delete" : "unknown");
+
+       return 1;
+}
+
+/*
+ * Check whether pool has some message queued for LV or for device_id
+ * When LV is NULL and device_id is 0 it just checks for any message.
+ */
+int pool_has_message(const struct lv_segment *seg,
+                    const struct logical_volume *lv, uint32_t device_id)
+{
+       const struct lv_thin_message *tmsg;
+
+       if (!seg_is_thin_pool(seg)) {
+               log_error(INTERNAL_ERROR "LV %s is not pool.", seg->lv->name);
+               return 0;
+       }
+
+       if (!lv && !device_id)
+               return dm_list_empty(&seg->thin_messages);
+
+       dm_list_iterate_items(tmsg, &seg->thin_messages) {
+               switch (tmsg->type) {
+               case DM_THIN_MESSAGE_CREATE_SNAP:
+               case DM_THIN_MESSAGE_CREATE_THIN:
+                       if (tmsg->u.lv == lv)
+                               return 1;
+                       break;
+               case DM_THIN_MESSAGE_DELETE:
+                       if (tmsg->u.delete_id == device_id)
+                               return 1;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+int pool_below_threshold(const struct lv_segment *pool_seg)
+{
+       percent_t percent;
+       int threshold = PERCENT_1 *
+               find_config_tree_int(pool_seg->lv->vg->cmd,
+                                    "activation/thin_pool_autoextend_threshold",
+                                    DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD);
+
+       /* Data */
+       if (!lv_thin_pool_percent(pool_seg->lv, 0, &percent))
+               return_0;
+
+       if (percent >= threshold)
+               return_0;
+
+       /* Metadata */
+       if (!lv_thin_pool_percent(pool_seg->lv, 1, &percent))
+               return_0;
+
+       if (percent >= threshold)
+               return_0;
+
+       return 1;
+}
+
+struct lv_segment *find_pool_seg(const struct lv_segment *seg)
+{
+       struct lv_segment *pool_seg;
+
+       pool_seg = get_only_segment_using_this_lv(seg->lv);
+
+       if (!pool_seg) {
+               log_error("Failed to find pool_seg for %s", seg->lv->name);
+               return NULL;
+       }
+
+       if (!seg_is_thin_pool(pool_seg)) {
+               log_error("%s on %s is not a pool segment",
+                         pool_seg->lv->name, seg->lv->name);
+               return NULL;
+       }
+
+       return pool_seg;
+}
+
+/*
+ * Find a free device_id for given thin_pool segment.
+ *
+ * \return
+ * Free device id, or 0 if free device_id is not found.
+ *
+ * FIXME: Improve naive search and keep the value cached
+ * and updated during VG lifetime (so no const for lv_segment)
+ */
+uint32_t get_free_pool_device_id(struct lv_segment *thin_pool_seg)
+{
+       uint32_t max_id = 0;
+       struct seg_list *sl;
+
+       if (!seg_is_thin_pool(thin_pool_seg)) {
+               log_error(INTERNAL_ERROR
+                         "Segment in %s is not a thin pool segment.",
+                         thin_pool_seg->lv->name);
+               return 0;
+       }
+
+       dm_list_iterate_items(sl, &thin_pool_seg->lv->segs_using_this_lv)
+               if (sl->seg->device_id > max_id)
+                       max_id = sl->seg->device_id;
+
+       if (++max_id > DM_THIN_MAX_DEVICE_ID) {
+               /* FIXME Find empty holes instead of aborting! */
+               log_error("Cannot find free device_id.");
+               return 0;
+       }
+
+       log_debug("Found free pool device_id %u.", max_id);
+
+       return max_id;
+}
+
+// FIXME Rename this fn: it doesn't extend an already-existing pool AFAICT
+int extend_pool(struct logical_volume *pool_lv, const struct segment_type *segtype,
+               struct alloc_handle *ah, uint32_t stripes, uint32_t stripe_size)
+{
+       const struct segment_type *striped;
+       struct logical_volume *meta_lv, *data_lv;
+       struct lv_segment *seg;
+       const size_t len = strlen(pool_lv->name) + 16;
+       char name[len];
+
+       if (pool_lv->le_count) {
+               /* FIXME move code for manipulation from lv_manip.c */
+               log_error(INTERNAL_ERROR "Pool %s has already extents.", pool_lv->name);
+               return 0;
+       }
+
+       /* LV is not yet a pool, so it's extension from lvcreate */
+       if (!(striped = get_segtype_from_string(pool_lv->vg->cmd, "striped")))
+               return_0;
+
+       if (activation() && segtype->ops->target_present &&
+           !segtype->ops->target_present(pool_lv->vg->cmd, NULL, NULL)) {
+               log_error("%s: Required device-mapper target(s) not "
+                         "detected in your kernel.", segtype->name);
+               return 0;
+       }
+
+       /* Metadata segment */
+       if (!lv_add_segment(ah, stripes, 1, pool_lv, striped, 1, 0, 0))
+               return_0;
+
+       if (activation()) {
+               if (!vg_write(pool_lv->vg) || !vg_commit(pool_lv->vg))
+                       return_0;
+
+               /*
+                * If killed here, only the VISIBLE striped pool LV is left
+                * and user could easily remove it.
+                *
+                * FIXME: implement lazy clearing when activation is disabled
+                */
+
+               /* pool_lv is a new LV so the VG lock protects us */
+               if (!activate_lv_local(pool_lv->vg->cmd, pool_lv) ||
+                   /* Clear 4KB of metadata device for new thin-pool. */
+                   !set_lv(pool_lv->vg->cmd, pool_lv, UINT64_C(0), 0)) {
+                       log_error("Aborting. Failed to wipe pool metadata %s.",
+                                 pool_lv->name);
+                       return 0;
+               }
+
+               if (!deactivate_lv_local(pool_lv->vg->cmd, pool_lv)) {
+                       log_error("Aborting. Could not deactivate pool metadata %s.",
+                                 pool_lv->name);
+                       return 0;
+               }
+       } else {
+               log_warn("WARNING: Pool %s is created without initialization.", pool_lv->name);
+       }
+
+       if (dm_snprintf(name, len, "%s_tmeta", pool_lv->name) < 0)
+               return_0;
+
+       if (!(meta_lv = lv_create_empty(name, NULL, LVM_READ | LVM_WRITE,
+                                       ALLOC_INHERIT, pool_lv->vg)))
+               return_0;
+
+       if (!move_lv_segments(meta_lv, pool_lv, 0, 0))
+               return_0;
+
+       /* Pool data segment */
+       if (!lv_add_segment(ah, 0, stripes, pool_lv, striped, stripe_size, 0, 0))
+               return_0;
+
+       if (!(data_lv = insert_layer_for_lv(pool_lv->vg->cmd, pool_lv,
+                                           pool_lv->status, "_tdata")))
+               return_0;
+
+       seg = first_seg(pool_lv);
+       seg->segtype = segtype; /* Set as thin_pool segment */
+       seg->lv->status |= THIN_POOL;
+
+       if (!attach_pool_metadata_lv(seg, meta_lv))
+               return_0;
+
+       /* Drop reference as attach_pool_data_lv() takes it again */
+       remove_seg_from_segs_using_this_lv(data_lv, seg);
+       if (!attach_pool_data_lv(seg, data_lv))
+               return_0;
+
+       return 1;
+}
+
+int update_pool_lv(struct logical_volume *lv, int activate)
+{
+       int monitored;
+
+       if (!lv_is_thin_pool(lv)) {
+               log_error(INTERNAL_ERROR "Updated LV %s is not pool.", lv->name);
+               return 0;
+       }
+
+       if (dm_list_empty(&(first_seg(lv)->thin_messages)))
+               return 1; /* No messages */
+
+       if (activate) {
+               /* If the pool is not active, do activate deactivate */
+               if (!lv_is_active(lv)) {
+                       monitored = dmeventd_monitor_mode();
+                       init_dmeventd_monitor(DMEVENTD_MONITOR_IGNORE);
+                       if (!activate_lv_excl(lv->vg->cmd, lv))
+                               return_0;
+                       if (!deactivate_lv(lv->vg->cmd, lv))
+                               return_0;
+                       init_dmeventd_monitor(monitored);
+               }
+               /*
+                * Resume active pool to send thin messages.
+                * origin_only is used to skip check for resumed state
+                */
+               else if (!resume_lv_origin(lv->vg->cmd, lv)) {
+                       log_error("Failed to resume %s.", lv->name);
+                       return 0;
+               }
+       }
+
+       dm_list_init(&(first_seg(lv)->thin_messages));
+
+       if (!vg_write(lv->vg) || !vg_commit(lv->vg))
+               return_0;
+
+       backup(lv->vg);
+
+       return 1;
+}
+
+int get_pool_discards(const char *str, thin_discards_t *discards)
+{
+       if (!strcasecmp(str, "passdown"))
+               *discards = THIN_DISCARDS_PASSDOWN;
+       else if (!strcasecmp(str, "nopassdown"))
+               *discards = THIN_DISCARDS_NO_PASSDOWN;
+       else if (!strcasecmp(str, "ignore"))
+               *discards = THIN_DISCARDS_IGNORE;
+       else {
+               log_error("Thin pool discards type %s is unknown.", str);
+               return 0;
+       }
+
+       return 1;
+}
+
+const char *get_pool_discards_name(thin_discards_t discards)
+{
+       switch (discards) {
+       case THIN_DISCARDS_PASSDOWN:
+                return "passdown";
+       case THIN_DISCARDS_NO_PASSDOWN:
+               return "nopassdown";
+       case THIN_DISCARDS_IGNORE:
+               return "ignore";
+       }
+
+       log_error(INTERNAL_ERROR "Unknown discards type encountered.");
+
+       return "unknown";
+}
index 9d0d5dd722c878ab3c7fb4382dce103a71af5f25..2897d426bbf3e19ac53395d29da5a42985391221 100644 (file)
 #include "metadata.h"
 #include "display.h"
 #include "activate.h"
+#include "toolcontext.h"
+#include "lvmcache.h"
+
+struct volume_group *alloc_vg(const char *pool_name, struct cmd_context *cmd,
+                             const char *vg_name)
+{
+       struct dm_pool *vgmem;
+       struct volume_group *vg;
+
+       if (!(vgmem = dm_pool_create(pool_name, VG_MEMPOOL_CHUNK)) ||
+           !(vg = dm_pool_zalloc(vgmem, sizeof(*vg)))) {
+               log_error("Failed to allocate volume group structure");
+               if (vgmem)
+                       dm_pool_destroy(vgmem);
+               return NULL;
+       }
+
+       if (vg_name && !(vg->name = dm_pool_strdup(vgmem, vg_name))) {
+               log_error("Failed to allocate VG name.");
+               dm_pool_destroy(vgmem);
+               return NULL;
+       }
+
+       vg->cmd = cmd;
+       vg->vgmem = vgmem;
+       vg->alloc = ALLOC_NORMAL;
+
+       if (!(vg->hostnames = dm_hash_create(16))) {
+               log_error("Failed to allocate VG hostname hashtable.");
+               dm_pool_destroy(vgmem);
+               return NULL;
+       }
+
+       dm_list_init(&vg->pvs);
+       dm_list_init(&vg->pvs_to_create);
+       dm_list_init(&vg->lvs);
+       dm_list_init(&vg->tags);
+       dm_list_init(&vg->removed_pvs);
+
+       log_debug("Allocated VG %s at %p.", vg->name, vg);
+
+       return vg;
+}
+
+static void _free_vg(struct volume_group *vg)
+{
+       vg_set_fid(vg, NULL);
+
+       if (vg->cmd && vg->vgmem == vg->cmd->mem) {
+               log_error(INTERNAL_ERROR "global memory pool used for VG %s",
+                         vg->name);
+               return;
+       }
+
+       log_debug("Freeing VG %s at %p.", vg->name, vg);
+
+       dm_hash_destroy(vg->hostnames);
+       dm_pool_destroy(vg->vgmem);
+}
+
+void release_vg(struct volume_group *vg)
+{
+       if (!vg || (vg->fid && vg == vg->fid->fmt->orphan_vg))
+               return;
+
+       /* Check if there are any vginfo holders */
+       if (vg->vginfo &&
+           !lvmcache_vginfo_holders_dec_and_test_for_zero(vg->vginfo))
+               return;
+
+       _free_vg(vg);
+}
+
+/*
+ * FIXME out of place, but the main (cmd) pool has been already
+ * destroyed and touching the fid (also via release_vg) will crash the
+ * program
+ *
+ * For now quick wrapper to allow destroy of orphan vg
+ */
+void free_orphan_vg(struct volume_group *vg)
+{
+       _free_vg(vg);
+}
 
 char *vg_fmt_dup(const struct volume_group *vg)
 {
@@ -196,7 +280,7 @@ static int _recalc_extents(uint32_t *extents, const char *desc1,
 
        size /= new_size;
 
-       if (size > UINT32_MAX) {
+       if (size > MAX_EXTENT_COUNT) {
                log_error("New extent count %" PRIu64 " for %s%s exceeds "
                          "32 bits.", size, desc1, desc2);
                return 0;
@@ -430,12 +514,25 @@ int vg_set_clustered(struct volume_group *vg, int clustered)
 
        /*
         * We do not currently support switching the cluster attribute
-        * on active mirrors or snapshots.
+        * on active mirrors, snapshots or RAID logical volumes.
         */
        dm_list_iterate_items(lvl, &vg->lvs) {
-               if (lv_is_mirrored(lvl->lv) && lv_is_active(lvl->lv)) {
-                       log_error("Mirror logical volumes must be inactive "
-                                 "when changing the cluster attribute.");
+               /*
+                * FIXME:
+                * We could allow exclusive activation of RAID LVs, but
+                * for now we disallow them in a cluster VG at all.
+                */
+               if (lv_is_raid_type(lvl->lv)) {
+                       log_error("RAID logical volumes are not allowed "
+                                 "in a cluster volume group.");
+                       return 0;
+               }
+
+               if (lv_is_active(lvl->lv) &&
+                   (lv_is_mirrored(lvl->lv) || lv_is_raid_type(lvl->lv))) {
+                       log_error("%s logical volumes must be inactive "
+                                 "when changing the cluster attribute.",
+                                 lv_is_raid_type(lvl->lv) ? "RAID" : "Mirror");
                        return 0;
                }
 
index 448dcfe4b498264d6d70f65dabc6e2bba0fd3d5c..f876968c3bb21065ec32df51450f528fcc844878 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -31,10 +31,19 @@ typedef enum {
        ALLOC_INHERIT
 } alloc_policy_t;
 
+struct pv_to_create {
+       struct dm_list list;
+       struct physical_volume *pv;
+       struct pvcreate_params *pp;
+};
+
+#define MAX_EXTENT_COUNT  (UINT32_MAX)
+
 struct volume_group {
        struct cmd_context *cmd;
        struct dm_pool *vgmem;
        struct format_instance *fid;
+       struct lvmcache_vginfo *vginfo;
        struct dm_list *cmd_vgs;/* List of wanted/locked and opened VGs */
        uint32_t cmd_missing_vgs;/* Flag marks missing VG */
        uint32_t seqno;         /* Metadata sequence number */
@@ -58,6 +67,13 @@ struct volume_group {
        uint32_t pv_count;
        struct dm_list pvs;
 
+       /*
+        * List of physical volumes that were used in vgextend but do not carry
+        * a PV label yet. They need to be pvcreate'd at vg_write time.
+        */
+
+       struct dm_list pvs_to_create;
+
        /*
         * logical volumes
         * The following relationship should always hold:
@@ -93,8 +109,20 @@ struct volume_group {
         */
        uint32_t read_status;
        uint32_t mda_copies; /* target number of mdas for this VG */
+
+       struct dm_hash_table *hostnames; /* map of creation hostnames */
 };
 
+struct volume_group *alloc_vg(const char *pool_name, struct cmd_context *cmd,
+                             const char *vg_name);
+
+/*
+ * release_vg() must be called on every struct volume_group allocated
+ * by vg_create() or vg_read_internal() to free it when no longer required.
+ */
+void release_vg(struct volume_group *vg);
+void free_orphan_vg(struct volume_group *vg);
+
 char *vg_fmt_dup(const struct volume_group *vg);
 char *vg_name_dup(const struct volume_group *vg);
 char *vg_system_id_dup(const struct volume_group *vg);
@@ -117,10 +145,12 @@ uint32_t vg_mda_count(const struct volume_group *vg);
 uint32_t vg_mda_used_count(const struct volume_group *vg);
 uint32_t vg_mda_copies(const struct volume_group *vg);
 int vg_set_mda_copies(struct volume_group *vg, uint32_t mda_copies);
+
 /*
  * Returns visible LV count - number of LVs from user perspective
  */
 unsigned vg_visible_lvs(const struct volume_group *vg);
+
 /*
  * Count snapshot LVs.
  */
index 3d25d7092439e518a276a29021f64e1442b185d6..7ce847595e036021ff4f30c490d12decdad99636 100644 (file)
 #include "lvm-string.h"
 #include "targets.h"
 #include "activate.h"
-#include "sharedlib.h"
 #include "str_list.h"
 
 #include <sys/utsname.h>
 
-static int _block_on_error_available = 0;
-static unsigned _mirror_attributes = 0;
-
 enum {
        MIRR_DISABLED,
        MIRR_RUNNING,
@@ -72,55 +68,50 @@ static void _mirrored_display(const struct lv_segment *seg)
        log_print(" ");
 }
 
-static int _mirrored_text_import_area_count(const struct config_node *sn, uint32_t *area_count)
+static int _mirrored_text_import_area_count(const struct dm_config_node *sn, uint32_t *area_count)
 {
-       if (!get_config_uint32(sn, "mirror_count", area_count)) {
+       if (!dm_config_get_uint32(sn, "mirror_count", area_count)) {
                log_error("Couldn't read 'mirror_count' for "
-                         "segment '%s'.", config_parent_name(sn));
+                         "segment '%s'.", dm_config_parent_name(sn));
                return 0;
        }
 
        return 1;
 }
 
-static int _mirrored_text_import(struct lv_segment *seg, const struct config_node *sn,
+static int _mirrored_text_import(struct lv_segment *seg, const struct dm_config_node *sn,
                        struct dm_hash_table *pv_hash)
 {
-       const struct config_node *cn;
+       const struct dm_config_value *cv;
        const char *logname = NULL;
 
-       if (find_config_node(sn, "extents_moved")) {
-               if (get_config_uint32(sn, "extents_moved",
+       if (dm_config_has_node(sn, "extents_moved")) {
+               if (dm_config_get_uint32(sn, "extents_moved",
                                      &seg->extents_copied))
                        seg->status |= PVMOVE;
                else {
                        log_error("Couldn't read 'extents_moved' for "
                                  "segment %s of logical volume %s.",
-                                 config_parent_name(sn), seg->lv->name);
+                                 dm_config_parent_name(sn), seg->lv->name);
                        return 0;
                }
        }
 
-       if (find_config_node(sn, "region_size")) {
-               if (!get_config_uint32(sn, "region_size",
+       if (dm_config_has_node(sn, "region_size")) {
+               if (!dm_config_get_uint32(sn, "region_size",
                                      &seg->region_size)) {
                        log_error("Couldn't read 'region_size' for "
                                  "segment %s of logical volume %s.",
-                                 config_parent_name(sn), seg->lv->name);
+                                 dm_config_parent_name(sn), seg->lv->name);
                        return 0;
                }
        }
 
-       if ((cn = find_config_node(sn, "mirror_log"))) {
-               if (!cn->v || !cn->v->v.str) {
-                       log_error("Mirror log type must be a string.");
-                       return 0;
-               }
-               logname = cn->v->v.str;
+       if (dm_config_get_str(sn, "mirror_log", &logname)) {
                if (!(seg->log_lv = find_lv(seg->lv->vg, logname))) {
                        log_error("Unrecognised mirror log in "
                                  "segment %s of logical volume %s.",
-                                 config_parent_name(sn), seg->lv->name);
+                                 dm_config_parent_name(sn), seg->lv->name);
                        return 0;
                }
                seg->log_lv->status |= MIRROR_LOG;
@@ -129,18 +120,18 @@ static int _mirrored_text_import(struct lv_segment *seg, const struct config_nod
        if (logname && !seg->region_size) {
                log_error("Missing region size for mirror log for "
                          "segment %s of logical volume %s.",
-                         config_parent_name(sn), seg->lv->name);
+                         dm_config_parent_name(sn), seg->lv->name);
                return 0;
        }
 
-       if (!(cn = find_config_node(sn, "mirrors"))) {
+       if (!dm_config_get_list(sn, "mirrors", &cv)) {
                log_error("Couldn't find mirrors array for "
                          "segment %s of logical volume %s.",
-                         config_parent_name(sn), seg->lv->name);
+                         dm_config_parent_name(sn), seg->lv->name);
                return 0;
        }
 
-       return text_import_areas(seg, sn, cn, pv_hash, MIRROR_IMAGE);
+       return text_import_areas(seg, sn, cv, pv_hash, MIRROR_IMAGE);
 }
 
 static int _mirrored_text_export(const struct lv_segment *seg, struct formatter *f)
@@ -158,6 +149,9 @@ static int _mirrored_text_export(const struct lv_segment *seg, struct formatter
 }
 
 #ifdef DEVMAPPER_SUPPORT
+static int _block_on_error_available = 0;
+static unsigned _mirror_attributes = 0;
+
 static struct mirror_state *_mirrored_init_target(struct dm_pool *mem,
                                         struct cmd_context *cmd)
 {
@@ -184,7 +178,6 @@ static int _mirrored_target_percent(void **target_state,
                                    uint64_t *total_numerator,
                                    uint64_t *total_denominator)
 {
-       struct mirror_state *mirr_state;
        uint64_t numerator, denominator;
        unsigned mirror_count, m;
        int used;
@@ -193,8 +186,6 @@ static int _mirrored_target_percent(void **target_state,
        if (!*target_state)
                *target_state = _mirrored_init_target(mem, cmd);
 
-       mirr_state = *target_state;
-
        /* Status line: <#mirrors> (maj:min)+ <synced>/<total_regions> */
        log_debug("Mirror status: %s", params);
 
@@ -234,14 +225,14 @@ static int _mirrored_target_percent(void **target_state,
 
 static int _mirrored_transient_status(struct lv_segment *seg, char *params)
 {
-       int i, j;
+       unsigned i, j;
        struct logical_volume *lv = seg->lv;
        struct lvinfo info;
        char *p = NULL;
        char **args, **log_args;
        struct logical_volume **images;
        struct logical_volume *log;
-       int num_devs, log_argc;
+       unsigned num_devs, log_argc;
        int failed = 0;
        char *status;
 
@@ -251,7 +242,7 @@ static int _mirrored_transient_status(struct lv_segment *seg, char *params)
        if (!dm_split_words(params, 1, 0, &p))
                return_0;
 
-       if (!(num_devs = atoi(p)))
+       if (!(num_devs = (unsigned) atoi(p)))
                return_0;
 
        p += strlen(p) + 1;
@@ -259,33 +250,34 @@ static int _mirrored_transient_status(struct lv_segment *seg, char *params)
        if (num_devs > DEFAULT_MIRROR_MAX_IMAGES) {
                log_error("Unexpectedly many (%d) mirror images in %s.",
                          num_devs, lv->name);
-               return_0;
+               return 0;
        }
 
        args = alloca((num_devs + 5) * sizeof(char *));
        images = alloca(num_devs * sizeof(struct logical_volume *));
 
-       if (dm_split_words(p, num_devs + 4, 0, args) < num_devs + 4)
+       /* FIXME: dm_split_words()  should return unsigned */
+       if ((unsigned)dm_split_words(p, num_devs + 4, 0, args) < num_devs + 4)
                return_0;
 
-       log_argc = atoi(args[3 + num_devs]);
-       log_args = alloca(log_argc * sizeof(char *));
+       log_argc = (unsigned) atoi(args[3 + num_devs]);
 
        if (log_argc > 16) {
                log_error("Unexpectedly many (%d) log arguments in %s.",
                          log_argc, lv->name);
-               return_0;
+               return 0;
        }
 
+       log_args = alloca(log_argc * sizeof(char *));
 
-       if (dm_split_words(args[3 + num_devs] + strlen(args[3 + num_devs]) + 1,
-                          log_argc, 0, log_args) < log_argc)
+       if ((unsigned)dm_split_words(args[3 + num_devs] + strlen(args[3 + num_devs]) + 1,
+                                    log_argc, 0, log_args) < log_argc)
                return_0;
 
        if (num_devs != seg->area_count) {
                log_error("Active mirror has a wrong number of mirror images!");
                log_error("Metadata says %d, kernel says %d.", seg->area_count, num_devs);
-               return_0;
+               return 0;
        }
 
        if (!strcmp(log_args[0], "disk")) {
@@ -301,7 +293,7 @@ static int _mirrored_transient_status(struct lv_segment *seg, char *params)
                if (strcmp(buf, log_args[1])) {
                        log_error("Mirror log mismatch. Metadata says %s, kernel says %s.",
                                  buf, log_args[1]);
-                       return_0;
+                       return 0;
                }
                log_very_verbose("Status of log (%s): %s", buf, log_args[2]);
                if (log_args[2][0] != 'A') {
@@ -335,7 +327,7 @@ static int _mirrored_transient_status(struct lv_segment *seg, char *params)
        for (i = 0; i < num_devs; ++i) {
                if (!images[i]) {
                        log_error("Failed to find image %d (%s).", i, args[i]);
-                       return_0;
+                       return 0;
                }
                log_very_verbose("Status of image %d: %c", i, status[i]);
                if (status[i] != 'A') {
@@ -346,12 +338,13 @@ static int _mirrored_transient_status(struct lv_segment *seg, char *params)
 
        /* update PARTIAL_LV flags across the VG */
        if (failed)
-               vg_mark_partial_lvs(lv->vg);
+               vg_mark_partial_lvs(lv->vg, 0);
 
        return 1;
 }
 
 static int _add_log(struct dm_pool *mem, struct lv_segment *seg,
+                   const struct lv_activate_opts *laopts,
                    struct dm_tree_node *node, uint32_t area_count, uint32_t region_size)
 {
        unsigned clustered = 0;
@@ -362,8 +355,7 @@ static int _add_log(struct dm_pool *mem, struct lv_segment *seg,
         * Use clustered mirror log for non-exclusive activation
         * in clustered VG.
         */
-       if ((!(seg->lv->status & ACTIVATE_EXCL) &&
-             (vg_is_clustered(seg->lv->vg))))
+       if (!laopts->exclusive && vg_is_clustered(seg->lv->vg))
                clustered = 1;
 
        if (seg->log_lv) {
@@ -393,10 +385,11 @@ static int _add_log(struct dm_pool *mem, struct lv_segment *seg,
 }
 
 static int _mirrored_add_target_line(struct dev_manager *dm, struct dm_pool *mem,
-                               struct cmd_context *cmd, void **target_state,
-                               struct lv_segment *seg,
-                               struct dm_tree_node *node, uint64_t len,
-                               uint32_t *pvmove_mirror_count)
+                                    struct cmd_context *cmd, void **target_state,
+                                    struct lv_segment *seg,
+                                    const struct lv_activate_opts *laopts,
+                                    struct dm_tree_node *node, uint64_t len,
+                                    uint32_t *pvmove_mirror_count)
 {
        struct mirror_state *mirr_state;
        uint32_t area_count = seg->area_count;
@@ -405,8 +398,9 @@ static int _mirrored_add_target_line(struct dev_manager *dm, struct dm_pool *mem
        uint32_t region_size;
        int r;
 
-       if (!*target_state)
-               *target_state = _mirrored_init_target(mem, cmd);
+       if (!*target_state &&
+           !(*target_state = _mirrored_init_target(mem, cmd)))
+                return_0;
 
        mirr_state = *target_state;
 
@@ -434,7 +428,9 @@ static int _mirrored_add_target_line(struct dev_manager *dm, struct dm_pool *mem
        }
 
        if (mirror_status != MIRR_RUNNING) {
-               if (!dm_tree_node_add_linear_target(node, len))
+               if (!add_linear_area_to_dtree(node, len, seg->lv->vg->extent_size,
+                                             cmd->use_linear_target,
+                                             seg->lv->vg->name, seg->lv->name))
                        return_0;
                goto done;
        }
@@ -454,7 +450,7 @@ static int _mirrored_add_target_line(struct dev_manager *dm, struct dm_pool *mem
        if (!dm_tree_node_add_mirror_target(node, len))
                return_0;
 
-       if ((r = _add_log(mem, seg, node, area_count, region_size)) <= 0) {
+       if ((r = _add_log(mem, seg, laopts, node, area_count, region_size)) <= 0) {
                stack;
                return r;
        }
@@ -616,11 +612,11 @@ static struct segtype_handler _mirrored_ops = {
        .target_percent = _mirrored_target_percent,
        .target_present = _mirrored_target_present,
        .check_transient_status = _mirrored_transient_status,
-#ifdef DMEVENTD
+#  ifdef DMEVENTD
        .target_monitored = _target_registered,
        .target_monitor_events = _target_monitor_events,
        .target_unmonitor_events = _target_unmonitor_events,
-#endif
+#  endif       /* DMEVENTD */
 #endif
        .modules_needed = _mirrored_modules_needed,
        .destroy = _mirrored_destroy,
@@ -633,7 +629,7 @@ struct segment_type *init_segtype(struct cmd_context *cmd);
 struct segment_type *init_segtype(struct cmd_context *cmd)
 #endif
 {
-       struct segment_type *segtype = dm_malloc(sizeof(*segtype));
+       struct segment_type *segtype = dm_zalloc(sizeof(*segtype));
 
        if (!segtype)
                return_NULL;
@@ -644,9 +640,11 @@ struct segment_type *init_segtype(struct cmd_context *cmd)
        segtype->private = NULL;
        segtype->flags = SEG_AREAS_MIRRORED;
 
-#ifdef DMEVENTD
+#ifdef DEVMAPPER_SUPPORT
+#  ifdef DMEVENTD
        if (_get_mirror_dso_path(cmd))
                segtype->flags |= SEG_MONITORED;
+#  endif       /* DMEVENTD */
 #endif
 
        log_very_verbose("Initialised segtype: %s", segtype->name);
index d8e2db8ebf03bebe895d48519c2463937984fa01..fdc5a2617fbff2416892bc1d2b4cf3c235bdd7ac 100644 (file)
@@ -15,6 +15,9 @@
 /* Path to cmirrord pidfile. */
 #undef CMIRRORD_PIDFILE
 
+/* Define to 0 to exclude libSaCkpt. */
+#undef CMIRROR_HAS_CHECKPOINT
+
 /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
    systems. This function is required for `alloca.c' support on those systems.
    */
 /* Default data alignment. */
 #undef DEFAULT_DATA_ALIGNMENT
 
+/* Define default node creation behavior with dmsetup create */
+#undef DEFAULT_DM_ADD_NODE
+
+/* Define default name mangling behaviour */
+#undef DEFAULT_DM_NAME_MANGLING
+
+/* Default DM run directory. */
+#undef DEFAULT_DM_RUN_DIR
+
 /* Name of default locking directory. */
 #undef DEFAULT_LOCK_DIR
 
-/* Name of default run directory. */
+/* Default directory to keep PID files in. */
+#undef DEFAULT_PID_DIR
+
+/* Default LVM run directory. */
 #undef DEFAULT_RUN_DIR
 
 /* Define to 0 to reinstate the pre-2.02.54 handling of unit suffixes. */
 /* Define to 1 if canonicalize_file_name is available. */
 #undef HAVE_CANONICALIZE_FILE_NAME
 
-/* Define to 1 if you have the <ccs.h> header file. */
-#undef HAVE_CCS_H
-
 /* Define to 1 if your system has a working `chown' function. */
 #undef HAVE_CHOWN
 
+/* Define to 1 if you have the <corosync/cmap.h> header file. */
+#undef HAVE_COROSYNC_CMAP_H
+
 /* Define to 1 if you have the <corosync/confdb.h> header file. */
 #undef HAVE_COROSYNC_CONFDB_H
 
 /* Define to 1 if you have the <libgen.h> header file. */
 #undef HAVE_LIBGEN_H
 
-/* Define to 1 if you have the <libgulm.h> header file. */
-#undef HAVE_LIBGULM_H
-
 /* Define to 1 if you have the <libintl.h> header file. */
 #undef HAVE_LIBINTL_H
 
 /* Define to 1 if you have the `strtoul' function. */
 #undef HAVE_STRTOUL
 
-/* Define to 1 if `st_rdev' is member of `struct stat'. */
+/* Define to 1 if `st_rdev' is member of `struct stat'. */
 #undef HAVE_STRUCT_STAT_ST_RDEV
 
 /* Define to 1 if you have the <syslog.h> header file. */
 /* Define to 1 if you have the <utmpx.h> header file. */
 #undef HAVE_UTMPX_H
 
-/* Define to 1 if you have the <valgrind/memcheck.h> header file. */
-#undef HAVE_VALGRIND_MEMCHECK_H
-
 /* Define to 1 if you have the `vfork' function. */
 #undef HAVE_VFORK
 
 /* Define to 1 to include built-in support for LVM1 metadata. */
 #undef LVM1_INTERNAL
 
+/* Path to lvmetad pidfile. */
+#undef LVMETAD_PIDFILE
+
+/* Define to 1 to include code that uses lvmetad. */
+#undef LVMETAD_SUPPORT
+
 /* Path to lvm binary. */
 #undef LVM_PATH
 
 /* Define to the one symbol short name of this package. */
 #undef PACKAGE_TARNAME
 
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
 /* Define to the version of this package. */
 #undef PACKAGE_VERSION
 
 /* Define to 1 to include built-in support for GFS pool metadata. */
 #undef POOL_INTERNAL
 
+/* Define to 1 to include built-in support for raid. */
+#undef RAID_INTERNAL
+
 /* Define to 1 to include the LVM readline shell. */
 #undef READLINE_SUPPORT
 
 /* Define to 1 if you have the ANSI C header files. */
 #undef STDC_HEADERS
 
+/* The path to 'thin_check', if available. */
+#undef THIN_CHECK_CMD
+
+/* Define to 1 to include built-in support for thin provisioning. */
+#undef THIN_INTERNAL
+
 /* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
 #undef TIME_WITH_SYS_TIME
 
index 9f95c37b78b912efa4574ce3e029683bbace06c5..c948b7753db4dcb69e57b83f34ae1eae6a5ba677 100644 (file)
@@ -16,6 +16,7 @@
 #include "lib.h"
 
 #include "crc.h"
+#include "xlate.h"
 
 /* Calculate an endian-independent CRC of supplied buffer */
 #ifndef DEBUG_CRC32
@@ -65,7 +66,7 @@ static uint32_t _calc_crc_new(uint32_t initial, const uint8_t *buf, uint32_t siz
    
        /* Process 4 bytes per iteration */
        while (start < end) {
-               crc = crc ^ *start++;
+               crc = crc ^ xlate32(*start++);
                crc = crctab[crc & 0xff] ^ crc >> 8;
                crc = crctab[crc & 0xff] ^ crc >> 8;
                crc = crctab[crc & 0xff] ^ crc >> 8;
index 5cad79eb2996d8c51e717a279bf13230b12f667d..4b74a411a43c82c2ea97564afddb32ab15ab5a8d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -18,6 +18,7 @@
 #include "locking.h"
 #include "lvm-exec.h"
 #include "toolcontext.h"
+#include "activate.h"
 
 #include <unistd.h>
 #include <sys/wait.h>
@@ -34,7 +35,7 @@ static char *_verbose_args(const char *const argv[], char *buf, size_t sz)
        buf[0] = '\0';
        for (i = 0; argv[i]; i++) {
                if ((len = dm_snprintf(buf + pos, sz - pos,
-                                      "%s ", argv[i])) < 0)
+                                      " %s", argv[i])) < 0)
                        /* Truncated */
                        break;
                pos += len;
@@ -46,13 +47,22 @@ static char *_verbose_args(const char *const argv[], char *buf, size_t sz)
 /*
  * Execute and wait for external command
  */
-int exec_cmd(struct cmd_context *cmd, const char *const argv[], int *rstatus)
+int exec_cmd(struct cmd_context *cmd, const char *const argv[],
+            int *rstatus, int sync_needed)
 {
        pid_t pid;
        int status;
        char buf[PATH_MAX * 2];
 
-       log_verbose("Executing: %s", _verbose_args(argv, buf, sizeof(buf)));
+
+       if (rstatus)
+               *rstatus = -1;
+
+       if (sync_needed)
+               if (!sync_local_dev_names(cmd)) /* Flush ops and reset dm cookie */
+                       return_0;
+
+       log_verbose("Executing:%s", _verbose_args(argv, buf, sizeof(buf)));
 
        if ((pid = fork()) == -1) {
                log_error("fork failed: %s", strerror(errno));
@@ -66,14 +76,11 @@ int exec_cmd(struct cmd_context *cmd, const char *const argv[], int *rstatus)
                /* FIXME Fix effect of reset_locking on cache then include this */
                /* destroy_toolcontext(cmd); */
                /* FIXME Use execve directly */
-               execvp(argv[0], (char **const) argv);
+               execvp(argv[0], (char **) argv);
                log_sys_error("execvp", argv[0]);
                _exit(errno);
        }
 
-       if (rstatus)
-               *rstatus = -1;
-
        /* Parent */
        if (wait4(pid, &status, 0, NULL) != pid) {
                log_error("wait4 child process %u failed: %s", pid,
index 6d984f846743f3af75f6bb0d7c816c2368214972..c91ffafe4f313dbc281ce3830f306e2e843ba748 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.  
- * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
 #include "lib.h"
 
 struct cmd_context;
-int exec_cmd(struct cmd_context *cmd, const char *const argv[], int *rstatus);
+
+/**
+ * Execute command with paramaters and return status
+ *
+ * \param rstatus
+ * Returns command's exit status code.
+ *
+ * \param sync_needed
+ * Bool specifying whether local devices needs to be synchronized
+ * before executing command.
+ * Note: You cannot synchronize devices within activation context.
+ *
+ * \return
+ * 0 (success) or -1 (failure).
+ */
+int exec_cmd(struct cmd_context *cmd, const char *const argv[],
+            int *rstatus, int sync_needed);
 
 #endif
index f577840bfaf95310a81d93b0153e7e95cabc1a2c..b8e49cb343a43548f188f8cfb82cc52ea0e80d17 100644 (file)
@@ -15,7 +15,6 @@
 
 #include "lib.h"
 #include "lvm-file.h"
-#include "lvm-string.h"
 
 #include <unistd.h>
 #include <sys/stat.h>
@@ -35,6 +34,7 @@ int create_temp_name(const char *dir, char *buffer, size_t len, int *fd,
        int i, num;
        pid_t pid;
        char hostname[255];
+       char *p;
        struct flock lock = {
                .l_type = F_WRLCK,
                .l_whence = 0,
@@ -48,6 +48,12 @@ int create_temp_name(const char *dir, char *buffer, size_t len, int *fd,
                log_sys_error("gethostname", "");
                strcpy(hostname, "nohostname");
        }
+       else {
+               /* Replace any '/' with '?' found in the hostname. */
+               p = hostname;
+               while ((p = strchr(p, '/')))
+                       *p = '?';
+       }
 
        for (i = 0; i < 20; i++, num++) {
 
@@ -246,7 +252,8 @@ int fcntl_lock_file(const char *file, short lock_type, int warn_if_read_only)
 
        if (fcntl(lockfd, F_SETLKW, &lock)) {
                log_sys_error("fcntl", file);
-               close(lockfd);
+               if (close(lockfd))
+                        log_sys_error("close", file);
                return -1;
        }
 
index 07327c3572568bdab3ad5b56a6c4f5c0d99651ab..c23d8ad6510b4fa2b4484be87542571c9ea12b17 100644 (file)
@@ -51,6 +51,8 @@ void fcntl_unlock_file(int lockfd);
   ((buf1).st_ino == (buf2).st_ino && \
    (buf1).st_dev == (buf2).st_dev)
 
+#define is_valid_fd(fd) (!(fcntl(fd, F_GETFD) == -1 && errno == EBADF))
+
 /*
  * Close the specified stream, taking care to detect and diagnose any write
  * error.  If there is an error, use the supplied file name in a diagnostic
index 9da61fe05f0ee42e5a738756236fb75aab8d69e5..fe380089a88e0149ac5334278157b374ac5625f5 100644 (file)
 #include "device.h"
 #include "memlock.h"
 #include "lvm-string.h"
-#include "lvm-file.h"
 #include "defaults.h"
+#include "metadata-exported.h"
 
 #include <stdarg.h>
 
 static int _verbose_level = VERBOSE_BASE_LEVEL;
+static int _silent = 0;
 static int _test = 0;
 static int _md_filtering = 0;
 static int _pvmove = 0;
 static int _full_scan_done = 0;        /* Restrict to one full scan during each cmd */
+static int _obtain_device_list_from_udev = DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV;
 static int _trust_cache = 0; /* Don't scan when incomplete VGs encountered */
 static int _debug_level = 0;
 static int _log_cmd_name = 0;
@@ -40,18 +42,28 @@ static int _ignore_suspended_devices = 0;
 static int _error_message_produced = 0;
 static unsigned _is_static = 0;
 static int _udev_checking = 1;
+static int _retry_deactivation = DEFAULT_RETRY_DEACTIVATION;
+static int _activation_checks = 0;
 static char _sysfs_dir_path[PATH_MAX] = "";
 static int _dev_disable_after_error_count = DEFAULT_DISABLE_AFTER_ERROR_COUNT;
+static uint64_t _pv_min_size = (DEFAULT_PV_MIN_SIZE_KB * 1024L >> SECTOR_SHIFT);
+static int _detect_internal_vg_cache_corruption =
+       DEFAULT_DETECT_INTERNAL_VG_CACHE_CORRUPTION;
 
 void init_verbose(int level)
 {
        _verbose_level = level;
 }
 
+void init_silent(int silent)
+{
+       _silent = silent;
+}
+
 void init_test(int level)
 {
        if (!_test && level)
-               log_print("Test mode: Metadata will NOT be updated.");
+               log_warn("TEST MODE: Metadata will NOT be updated and volumes will not be (de)activated.");
        _test = level;
 }
 
@@ -70,6 +82,11 @@ void init_full_scan_done(int level)
        _full_scan_done = level;
 }
 
+void init_obtain_device_list_from_udev(int device_list_from_udev)
+{
+       _obtain_device_list_from_udev = device_list_from_udev;
+}
+
 void init_trust_cache(int trustcache)
 {
        _trust_cache = trustcache;
@@ -123,24 +140,47 @@ void init_udev_checking(int checking)
                log_debug("LVM udev checking disabled");
 }
 
+void init_retry_deactivation(int retry)
+{
+       _retry_deactivation = retry;
+}
+
+void init_activation_checks(int checks)
+{
+       if ((_activation_checks = checks))
+               log_debug("LVM activation checks enabled");
+       else
+               log_debug("LVM activation checks disabled");
+}
+
 void init_dev_disable_after_error_count(int value)
 {
        _dev_disable_after_error_count = value;
 }
 
+void init_pv_min_size(uint64_t sectors)
+{
+       _pv_min_size = sectors;
+}
+
+void init_detect_internal_vg_cache_corruption(int detect)
+{
+       _detect_internal_vg_cache_corruption = detect;
+}
+
 void set_cmd_name(const char *cmd)
 {
-       strncpy(_cmd_name, cmd, sizeof(_cmd_name));
+       strncpy(_cmd_name, cmd, sizeof(_cmd_name) - 1);
        _cmd_name[sizeof(_cmd_name) - 1] = '\0';
 }
 
 void set_sysfs_dir_path(const char *path)
 {
-       strncpy(_sysfs_dir_path, path, sizeof(_sysfs_dir_path));
+       strncpy(_sysfs_dir_path, path, sizeof(_sysfs_dir_path) - 1);
        _sysfs_dir_path[sizeof(_sysfs_dir_path) - 1] = '\0';
 }
 
-const char *log_command_name()
+const char *log_command_name(void)
 {
        if (!_log_cmd_name)
                return "";
@@ -158,42 +198,47 @@ int error_message_produced(void)
        return _error_message_produced;
 }
 
-int test_mode()
+int test_mode(void)
 {
        return _test;
 }
 
-int md_filtering()
+int md_filtering(void)
 {
        return _md_filtering;
 }
 
-int pvmove_mode()
+int pvmove_mode(void)
 {
        return _pvmove;
 }
 
-int full_scan_done()
+int full_scan_done(void)
 {
        return _full_scan_done;
 }
 
-int trust_cache()
+int obtain_device_list_from_udev(void)
+{
+       return _obtain_device_list_from_udev;
+}
+
+int trust_cache(void)
 {
        return _trust_cache;
 }
 
-int background_polling()
+int background_polling(void)
 {
        return _background_polling;
 }
 
-int ignorelockingfailure()
+int ignorelockingfailure(void)
 {
        return _ignorelockingfailure;
 }
 
-int security_level()
+int security_level(void)
 {
        return _security_level;
 }
@@ -218,16 +263,21 @@ void init_debug(int level)
        _debug_level = level;
 }
 
-int verbose_level()
+int verbose_level(void)
 {
        return _verbose_level;
 }
 
-int debug_level()
+int debug_level(void)
 {
        return _debug_level;
 }
 
+int silent_mode(void)
+{
+       return _silent;
+}
+
 unsigned is_static(void)
 {
        return _is_static;
@@ -238,7 +288,17 @@ int udev_checking(void)
        return _udev_checking;
 }
 
-const char *sysfs_dir_path()
+int retry_deactivation(void)
+{
+       return _retry_deactivation;
+}
+
+int activation_checks(void)
+{
+       return _activation_checks;
+}
+
+const char *sysfs_dir_path(void)
 {
        return _sysfs_dir_path;
 }
@@ -247,3 +307,13 @@ int dev_disable_after_error_count(void)
 {
        return _dev_disable_after_error_count;
 }
+
+uint64_t pv_min_size(void)
+{
+       return _pv_min_size;
+}
+
+int detect_internal_vg_cache_corruption(void)
+{
+       return _detect_internal_vg_cache_corruption;
+}
index 2fabbc7c1e5e145332ab9e56c15e396fd32b4da4..7fe3288e1ce04e7ab4986eb9aa40a804b854e765 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.  
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
 
 #define VERBOSE_BASE_LEVEL _LOG_WARN
 #define SECURITY_LEVEL 0
+#define PV_MIN_SIZE_KB 512
 
 void init_verbose(int level);
+void init_silent(int silent);
 void init_test(int level);
 void init_md_filtering(int level);
 void init_pvmove(int level);
 void init_full_scan_done(int level);
+void init_obtain_device_list_from_udev(int device_list_from_udev);
 void init_trust_cache(int trustcache);
 void init_debug(int level);
 void init_cmd_name(int status);
@@ -38,6 +41,10 @@ void init_error_message_produced(int produced);
 void init_is_static(unsigned value);
 void init_udev_checking(int checking);
 void init_dev_disable_after_error_count(int value);
+void init_pv_min_size(uint64_t sectors);
+void init_activation_checks(int checks);
+void init_detect_internal_vg_cache_corruption(int detect);
+void init_retry_deactivation(int retry);
 
 void set_cmd_name(const char *cmd_name);
 void set_sysfs_dir_path(const char *path);
@@ -46,8 +53,10 @@ int test_mode(void);
 int md_filtering(void);
 int pvmove_mode(void);
 int full_scan_done(void);
+int obtain_device_list_from_udev(void);
 int trust_cache(void);
 int verbose_level(void);
+int silent_mode(void);
 int debug_level(void);
 int ignorelockingfailure(void);
 int lockingfailed(void);
@@ -59,6 +68,10 @@ const char *log_command_name(void);
 unsigned is_static(void);
 int udev_checking(void);
 const char *sysfs_dir_path(void);
+uint64_t pv_min_size(void);
+int activation_checks(void);
+int detect_internal_vg_cache_corruption(void);
+int retry_deactivation(void);
 
 #define DMEVENTD_MONITOR_IGNORE -1
 int dmeventd_monitor_mode(void);
index a9251906a1194f93571c011a6cbad0944bae4b99..bf30a7ef841c01328e884e6d29a9e8da4c8dc914 100644 (file)
@@ -34,7 +34,8 @@ typedef enum {
        PERCENT_0 = 0,
        PERCENT_1 = 1000000,
        PERCENT_100 = 100 * PERCENT_1,
-       PERCENT_INVALID = -1
+       PERCENT_INVALID = -1,
+       PERCENT_MERGE_FAILED = -2
 } percent_range_t;
 
 float percent_to_float(percent_t v);
index 8fd2c041e3ee53df2e64800716dbba8cfcde2650..7e4bbdd23813742d971d1a201a18eeff71df7409 100644 (file)
@@ -43,260 +43,19 @@ int emit_to_buffer(char **buffer, size_t *size, const char *fmt, ...)
        return 1;
 }
 
-/*
- * Count occurences of 'c' in 'str' until we reach a null char.
- *
- * Returns:
- *  len - incremented for each char we encounter.
- *  count - number of occurrences of 'c' and 'c2'.
- */
-static void _count_chars(const char *str, size_t *len, int *count,
-                        const int c1, const int c2)
-{
-       const char *ptr;
-
-       for (ptr = str; *ptr; ptr++, (*len)++)
-               if (*ptr == c1 || *ptr == c2)
-                       (*count)++;
-}
-
-/*
- * Count occurences of 'c' in 'str' of length 'size'.
- *
- * Returns:
- *   Number of occurrences of 'c'
- */
-unsigned count_chars(const char *str, size_t len, const int c)
-{
-       size_t i;
-       unsigned count = 0;
-
-       for (i = 0; i < len; i++)
-               if (str[i] == c)
-                       count++;
-
-       return count;
-}
-
-/*
- * Length of string after escaping double quotes and backslashes.
- */
-size_t escaped_len(const char *str)
-{
-       size_t len = 1;
-       int count = 0;
-
-       _count_chars(str, &len, &count, '\"', '\\');
-
-       return count + len;
-}
-
-/*
- * Copies a string, quoting orig_char with quote_char.
- * Optionally also quote quote_char.
- */
-static void _quote_characters(char **out, const char *src,
-                             const int orig_char, const int quote_char,
-                             int quote_quote_char)
-{
-       while (*src) {
-               if (*src == orig_char ||
-                   (*src == quote_char && quote_quote_char))
-                       *(*out)++ = quote_char;
-
-               *(*out)++ = *src++;
-       }
-}
-
-static void _unquote_one_character(char *src, const char orig_char,
-                                  const char quote_char)
-{
-       char *out;
-       char s, n;
-
-       /* Optimise for the common case where no changes are needed. */
-       while ((s = *src++)) {
-               if (s == quote_char &&
-                   ((n = *src) == orig_char || n == quote_char)) {
-                       out = src++;
-                       *(out - 1) = n;
-
-                       while ((s = *src++)) {
-                               if (s == quote_char &&
-                                   ((n = *src) == orig_char || n == quote_char)) {
-                                       s = n;
-                                       src++;
-                               }
-                               *out = s;
-                               out++;
-                       }
-
-                       *out = '\0';
-                       return;
-               }
-       }
-}
-
-/*
- * Unquote each character given in orig_char array and unquote quote_char
- * as well. Also save the first occurrence of each character from orig_char
- * that was found unquoted in arr_substr_first_unquoted array. This way we can
- * process several characters in one go.
- */
-static void _unquote_characters(char *src, const char *orig_chars,
-                               const int num_orig_chars, 
-                               const char quote_char,
-                               char *arr_substr_first_unquoted[])
-{
-       char *out = src;
-       char c, s, n;
-       unsigned i;
-
-       while ((s = *src++)) {
-               for (i = 0; i < num_orig_chars; i++) {
-                       c = orig_chars[i];
-                       if (s == quote_char &&
-                           ((n = *src) == c || n == quote_char)) {
-                               s = n;
-                               src++;
-                               break;
-                       }
-                       if (arr_substr_first_unquoted && (s == c) &&
-                           !arr_substr_first_unquoted[i])
-                               arr_substr_first_unquoted[i] = out;
-               };
-               *out++ = s;
-       }
-
-       *out = '\0';
-}
-
-/*
- * Copies a string, quoting hyphens with hyphens.
- */
-static void _quote_hyphens(char **out, const char *src)
-{
-       _quote_characters(out, src, '-', '-', 0);
-}
-
-/*
- * <vg>-<lv>-<layer> or if !layer just <vg>-<lv>.
- */
-char *build_dm_name(struct dm_pool *mem, const char *vgname,
-                   const char *lvname, const char *layer)
-{
-       size_t len = 1;
-       int hyphens = 1;
-       char *r, *out;
-
-       _count_chars(vgname, &len, &hyphens, '-', 0);
-       _count_chars(lvname, &len, &hyphens, '-', 0);
-
-       if (layer && *layer) {
-               _count_chars(layer, &len, &hyphens, '-', 0);
-               hyphens++;
-       }
-
-       len += hyphens;
-
-       if (!(r = dm_pool_alloc(mem, len))) {
-               log_error("build_dm_name: Allocation failed for %" PRIsize_t
-                         " for %s %s %s.", len, vgname, lvname, layer);
-               return NULL;
-       }
-
-       out = r;
-       _quote_hyphens(&out, vgname);
-       *out++ = '-';
-       _quote_hyphens(&out, lvname);
-
-       if (layer && *layer) {
-               /* No hyphen if the layer begins with _ e.g. _mlog */
-               if (*layer != '_')
-                       *out++ = '-';
-               _quote_hyphens(&out, layer);
-       }
-       *out = '\0';
-
-       return r;
-}
-
-char *build_dm_uuid(struct dm_pool *mem, const char *lvid, const char *layer)
-{
-       char *dmuuid;
-       size_t len;
-
-       if (!layer)
-               layer = "";
-
-       len = sizeof(UUID_PREFIX) + strlen(lvid) + strlen(layer) + 1;
-
-       if (!(dmuuid = dm_pool_alloc(mem, len))) {
-               log_error("build_dm_name: Allocation failed for %" PRIsize_t
-                         " %s %s.", len, lvid, layer);
-               return NULL;
-       }
-
-       sprintf(dmuuid, UUID_PREFIX "%s%s%s", lvid, (*layer) ? "-" : "", layer);
-
-       return dmuuid;
-}
-
-/*
- * Copies a string, quoting double quotes with backslashes.
- */
-char *escape_double_quotes(char *out, const char *src)
-{
-       char *buf = out;
-
-       _quote_characters(&buf, src, '\"', '\\', 1);
-       *buf = '\0';
-
-       return out;
-}
-
-/*
- * Undo quoting in situ.
- */
-void unescape_double_quotes(char *src)
-{
-       _unquote_one_character(src, '\"', '\\');
-}
-
-/*
- * Unescape colons and "at" signs in situ and save the substrings
- * starting at the position of the first unescaped colon and the
- * first unescaped "at" sign. This is normally used to unescape
- * device names used as PVs.
- */
-void unescape_colons_and_at_signs(char *src,
-                                 char **substr_first_unquoted_colon,
-                                 char **substr_first_unquoted_at_sign)
-{
-       const char *orig_chars = ":@";
-       char *arr_substr_first_unquoted[] = {NULL, NULL, NULL};
-
-       _unquote_characters(src, orig_chars, 2, '\\', arr_substr_first_unquoted);
-
-       if (substr_first_unquoted_colon)
-               *substr_first_unquoted_colon = arr_substr_first_unquoted[0];
-
-       if (substr_first_unquoted_at_sign)
-               *substr_first_unquoted_at_sign = arr_substr_first_unquoted[1];
-}
-
 /*
  * A-Za-z0-9._-+/=!:&#
  */
 int validate_tag(const char *n)
 {
        register char c;
-       register int len = 0;
+       /* int len = 0; */
 
        if (!n || !*n)
                return 0;
 
-       while ((len++, c = *n++))
+       /* FIXME: Is unlimited tag size support needed ? */
+       while ((/* len++, */ c = *n++))
                if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+' && c != '/'
                    && c != '=' && c != '!' && c != ':' && c != '&' && c != '#')
                        return 0;
@@ -337,34 +96,40 @@ int validate_name(const char *n)
 
 int apply_lvname_restrictions(const char *name)
 {
-       if (!strncmp(name, "snapshot", 8)) {
-               log_error("Names starting \"snapshot\" are reserved. "
-                         "Please choose a different LV name.");
-               return 0;
-       }
-
-       if (!strncmp(name, "pvmove", 6)) {
-               log_error("Names starting \"pvmove\" are reserved. "
-                         "Please choose a different LV name.");
-               return 0;
-       }
+       const char *reserved_prefixes[] = {
+               "snapshot",
+               "pvmove",
+               NULL
+       };
+
+       const char *reserved_strings[] = {
+               "_mlog",
+               "_mimage",
+               "_rimage",
+               "_rmeta",
+               "_vorigin",
+               "_tdata",
+               "_tmeta",
+               NULL
+       };
 
-       if (strstr(name, "_mlog")) {
-               log_error("Names including \"_mlog\" are reserved. "
-                         "Please choose a different LV name.");
-               return 0;
-       }
+       unsigned i;
+       const char *s;
 
-       if (strstr(name, "_mimage")) {
-               log_error("Names including \"_mimage\" are reserved. "
-                         "Please choose a different LV name.");
-               return 0;
+       for (i = 0; (s = reserved_prefixes[i]); i++) {
+               if (!strncmp(name, s, strlen(s))) {
+                       log_error("Names starting \"%s\" are reserved. "
+                                 "Please choose a different LV name.", s);
+                       return 0;
+               }
        }
 
-       if (strstr(name, "_vorigin")) {
-               log_error("Names including \"_vorigin\" are reserved. "
-                         "Please choose a different LV name.");
-               return 0;
+       for (i = 0; (s = reserved_strings[i]); i++) {
+               if (strstr(name, s)) {
+                       log_error("Names including \"%s\" are reserved. "
+                                 "Please choose a different LV name.", s);
+                       return 0;
+               }
        }
 
        return 1;
@@ -380,3 +145,9 @@ int is_reserved_lvname(const char *name)
 
        return rc;
 }
+
+char *build_dm_uuid(struct dm_pool *mem, const char *lvid,
+                   const char *layer)
+{
+       return dm_build_dm_uuid(mem, UUID_PREFIX, lvid, layer);
+}
index 20f45c939b05f27d2743172905e60a077cc7520e..6be048d05d125bef8db729a310775635cb884c38 100644 (file)
@@ -27,8 +27,6 @@ struct pool;
 int emit_to_buffer(char **buffer, size_t *size, const char *fmt, ...)
   __attribute__ ((format(printf, 3, 4)));
 
-char *build_dm_name(struct dm_pool *mem, const char *vg,
-                    const char *lv, const char *layer);
 char *build_dm_uuid(struct dm_pool *mem, const char *lvid,
                    const char *layer);
 
@@ -38,36 +36,4 @@ int validate_tag(const char *n);
 int apply_lvname_restrictions(const char *name);
 int is_reserved_lvname(const char *name);
 
-/*
- * Returns number of occurrences of c in first len characters of str.
- */
-unsigned count_chars(const char *str, size_t len, const int c);
-
-/*
- * Returns what length of escaped string would be including terminating NUL.
- */
-size_t escaped_len(const char *str);
-
-/*
- * Copies a string from src to out. 
- * Double quotation marks and backslashes are quoted with a backslash.
- * Caller must ensure *out has enough space - see escaped_len().
- * Returns *out.
- */
-char *escape_double_quotes(char *out, const char *src);
-
-/*
- * Removes quoting of double quotation marks and backslashes in situ.
- */
-void unescape_double_quotes(char *src);
-
-/*
- * Unescape colons and at signs in situ and save the substring starting
- * at the position of the first unescaped colon and the first unescaped
- * "at" sign.
- */
-void unescape_colons_and_at_signs(char *src,
-                                 char **substr_first_unquoted_colon,
-                                 char **substr_first_unquoted_at_sign);
-
 #endif
index 3ab8a71352c90a7c4cda7d11b727cf30ad829c80..6cffae308bd71e817883de689f811b37f706f3f3 100644 (file)
 #include <unistd.h>
 #include <fcntl.h>
 
+#ifdef UDEV_SYNC_SUPPORT
+static const char _no_context_msg[] = "Udev library context not set.";
+struct udev *_udev;
+
+int udev_init_library_context(void)
+{
+       if (_udev)
+               udev_unref(_udev);
+
+       if (!(_udev = udev_new())) {
+               log_error("Failed to create udev library context.");
+               return 0;
+       }
+
+       return 1;
+}
+
+void udev_fin_library_context(void)
+{
+       udev_unref(_udev);
+       _udev = NULL;
+}
+
+int udev_is_running(void)
+{
+       struct udev_queue *udev_queue;
+       int r;
+
+       if (!_udev) {
+               log_debug(_no_context_msg);
+               goto bad;
+       }
+
+       if (!(udev_queue = udev_queue_new(_udev))) {
+               log_debug("Could not get udev state.");
+               goto bad;
+       }
+
+       r = udev_queue_get_udev_is_active(udev_queue);
+       udev_queue_unref(udev_queue);
+
+       return r;
+
+bad:
+       log_debug("Assuming udev is not running.");
+       return 0;
+}
+
+struct udev* udev_get_library_context(void)
+{
+       return _udev;
+}
+
+#else  /* UDEV_SYNC_SUPPORT */
+
+int udev_init_library_context(void)
+{
+       return 1;
+}
+
+void udev_fin_library_context(void)
+{
+}
+
+int udev_is_running(void)
+{
+       return 0;
+}
+
+#endif
+
 int lvm_getpagesize(void)
 {
        return getpagesize();
index 19a7f03cd580c479497fb9091e1bd8be74fd24f8..e43f83198c81bd685fa77f79c71dcf53586840da 100644 (file)
 #ifndef _LVM_WRAPPERS_H
 #define _LVM_WRAPPERS_H
 
+#ifdef UDEV_SYNC_SUPPORT
+#include <libudev.h>
+struct udev *udev_get_library_context(void);
+#endif
+
+int udev_init_library_context(void);
+void udev_fin_library_context(void);
+int udev_is_running(void);
+
 int lvm_getpagesize(void);
 
 /*
index cab2909e6877734c4b7091d9359a5c021188acfe..4c2d17824b42e796ded127dec21accdbb2c38341 100644 (file)
@@ -15,9 +15,7 @@
 
 #include "lib.h"
 #include "config.h"
-#include "lvm-string.h"
 #include "sharedlib.h"
-#include "toolcontext.h"
 
 #include <limits.h>
 #include <sys/stat.h>
@@ -34,8 +32,10 @@ void get_shared_library_path(struct cmd_context *cmd, const char *libname,
        if (libname[0] == '/' ||
            !(lib_dir = find_config_tree_str(cmd, "global/library_dir", 0)) ||
            (dm_snprintf(path, path_len, "%s/%s", lib_dir,
-                         libname) == -1) || stat(path, &info) == -1)
-               strncpy(path, libname, path_len);
+                        libname) == -1) || stat(path, &info) == -1) {
+               strncpy(path, libname, path_len - 1);
+               path[path_len - 1] = '\0';
+       }
 }
 
 void *load_shared_library(struct cmd_context *cmd, const char *libname,
index 62e1be86927f22ade9d8225e3055bc3270ba6d40..47b5586add8776aa2d378cec56728404e92b0cb1 100644 (file)
@@ -125,6 +125,5 @@ int cmp_timestamp(struct timestamp *t1, struct timestamp *t2)
 
 void destroy_timestamp(struct timestamp *t)
 {
-       if (t)
-               dm_free(t);
+       dm_free(t);
 }
diff --git a/lib/misc/util.c b/lib/misc/util.c
deleted file mode 100644 (file)
index 75c7afa..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU Lesser General Public License v.2.1.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/*
- * Return the address of the last file name component of NAME.
- * If NAME ends in a slash, return the empty string.
- */
-
-#include "lib.h"
-
-/* empty for now.  */
index 0bcfd219659296e53c0286b9895dcd9dde39e64b..a4534697c298783b308413525be18c96d281f1c7 100644 (file)
@@ -25,7 +25,7 @@
                     (void) (&_a == &_b); \
                     _a > _b ? _a : _b; })
 
-#ifdef __clang__
+#if defined(__clang__) || (defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6)
 #define uninitialized_var(x) x
 #else
 #define uninitialized_var(x) x = x
index 062b765a57cb377278a40d0db5296459a83cbd81..2240a1d1ade644dac401baa91c940b59edb4dc9a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
 
 #ifndef DEVMAPPER_SUPPORT
 
-void memlock_inc(struct cmd_context *cmd)
+void memlock_inc_daemon(struct cmd_context *cmd)
 {
        return;
 }
-void memlock_dec(struct cmd_context *cmd)
+
+void memlock_dec_daemon(struct cmd_context *cmd)
 {
        return;
 }
-int memlock(void)
+
+void critical_section_inc(struct cmd_context *cmd, const char *reason)
+{
+       return;
+}
+
+void critical_section_dec(struct cmd_context *cmd, const char *reason)
+{
+       return;
+}
+
+int critical_section(void)
 {
        return 0;
 }
@@ -45,6 +57,16 @@ void memlock_init(struct cmd_context *cmd)
        return;
 }
 
+void memlock_unlock(struct cmd_context *cmd)
+{
+       return;
+}
+
+void memlock_reset(void)
+{
+       return;
+}
+
 #else                          /* DEVMAPPER_SUPPORT */
 
 static size_t _size_stack;
@@ -52,7 +74,8 @@ static size_t _size_malloc_tmp;
 static size_t _size_malloc = 2000000;
 
 static void *_malloc_mem = NULL;
-static int _memlock_count = 0;
+static int _mem_locked = 0;
+static int _critical_section = 0;
 static int _memlock_count_daemon = 0;
 static int _priority;
 static int _default_priority;
@@ -66,9 +89,11 @@ static const char * const _ignore_maps[] = {
 /* default blacklist for maps */
 static const char * const _blacklist_maps[] = {
     "locale/locale-archive",
+    "/LC_MESSAGES/",
     "gconv/gconv-modules.cache",
     "/libreadline.so.",        /* not using readline during mlock */
     "/libncurses.so.", /* not using readline during mlock */
+    "/libtinfo.so.",   /* not using readline during mlock */
     "/libdl-",         /* not using dlopen,dlsym during mlock */
     /* "/libdevmapper-event.so" */
 };
@@ -99,9 +124,14 @@ static void _touch_memory(void *mem, size_t size)
 static void _allocate_memory(void)
 {
        void *stack_mem, *temp_malloc_mem;
+       struct rlimit limit;
 
-       if ((stack_mem = alloca(_size_stack)))
+       /* Check if we could preallocate requested stack */
+       if ((getrlimit (RLIMIT_STACK, &limit) == 0) &&
+           ((_size_stack * 2) < limit.rlim_cur) &&
+           ((stack_mem = alloca(_size_stack))))
                _touch_memory(stack_mem, _size_stack);
+       /* FIXME else warn user setting got ignored */
 
        if ((temp_malloc_mem = malloc(_size_malloc_tmp)))
                _touch_memory(temp_malloc_mem, _size_malloc_tmp);
@@ -121,14 +151,16 @@ static void _release_memory(void)
  * mlock/munlock memory areas from /proc/self/maps
  * format described in kernel/Documentation/filesystem/proc.txt
  */
-static int _maps_line(const struct config_node *cn, lvmlock_t lock,
-                     const char* line, size_t* mstats)
+static int _maps_line(const struct dm_config_node *cn, lvmlock_t lock,
+                     const char *line, size_t *mstats)
 {
-       const struct config_value *cv;
+       const struct dm_config_value *cv;
        long from, to;
-       int pos, i;
+       int pos;
+       unsigned i;
        char fr, fw, fx, fp;
        size_t sz;
+       const char *lock_str = (lock == LVM_MLOCK) ? "mlock" : "munlock";
 
        if (sscanf(line, "%lx-%lx %c%c%c%c%n",
                   &from, &to, &fr, &fw, &fx, &fp, &pos) != 6) {
@@ -138,16 +170,15 @@ static int _maps_line(const struct config_node *cn, lvmlock_t lock,
 
        /* Select readable maps */
        if (fr != 'r') {
-               log_debug("%s area unreadable %s : Skipping.",
-                         (lock == LVM_MLOCK) ? "mlock" : "munlock", line);
+               log_debug("%s area unreadable %s : Skipping.", lock_str, line);
                return 1;
        }
 
        /* always ignored areas */
        for (i = 0; i < sizeof(_ignore_maps) / sizeof(_ignore_maps[0]); ++i)
                if (strstr(line + pos, _ignore_maps[i])) {
-                       log_debug("mlock ignore filter '%s' matches '%s': Skipping.",
-                                 _ignore_maps[i], line);
+                       log_debug("%s ignore filter '%s' matches '%s': Skipping.",
+                                 lock_str, _ignore_maps[i], line);
                        return 1;
                }
 
@@ -156,25 +187,32 @@ static int _maps_line(const struct config_node *cn, lvmlock_t lock,
                /* If no blacklist configured, use an internal set */
                for (i = 0; i < sizeof(_blacklist_maps) / sizeof(_blacklist_maps[0]); ++i)
                        if (strstr(line + pos, _blacklist_maps[i])) {
-                               log_debug("mlock default filter '%s' matches '%s': Skipping.",
-                                         _blacklist_maps[i], line);
+                               log_debug("%s default filter '%s' matches '%s': Skipping.",
+                                         lock_str, _blacklist_maps[i], line);
                                return 1;
                        }
        } else {
                for (cv = cn->v; cv; cv = cv->next) {
-                       if ((cv->type != CFG_STRING) || !cv->v.str[0])
+                       if ((cv->type != DM_CFG_STRING) || !cv->v.str[0])
                                continue;
                        if (strstr(line + pos, cv->v.str)) {
-                               log_debug("mlock_filter '%s' matches '%s': Skipping.",
-                                         cv->v.str, line);
+                               log_debug("%s_filter '%s' matches '%s': Skipping.",
+                                         lock_str, cv->v.str, line);
                                return 1;
                        }
                }
        }
 
+#ifdef VALGRIND_POOL
+       /*
+        * Valgrind is continually eating memory while executing code
+        * so we need to deactivate check of locked memory size
+         */
+       sz -= sz; /* = 0, but avoids getting warning about dead assigment */
+
+#endif
        *mstats += sz;
-       log_debug("%s %10ldKiB %12lx - %12lx %c%c%c%c%s",
-                 (lock == LVM_MLOCK) ? "mlock" : "munlock",
+       log_debug("%s %10ldKiB %12lx - %12lx %c%c%c%c%s", lock_str,
                  ((long)sz + 1023) / 1024, from, to, fr, fw, fx, fp, line + pos);
 
        if (lock == LVM_MLOCK) {
@@ -194,7 +232,7 @@ static int _maps_line(const struct config_node *cn, lvmlock_t lock,
 
 static int _memlock_maps(struct cmd_context *cmd, lvmlock_t lock, size_t *mstats)
 {
-       const struct config_node *cn;
+       const struct dm_config_node *cn;
        char *line, *line_end;
        size_t len;
        ssize_t n;
@@ -236,7 +274,8 @@ static int _memlock_maps(struct cmd_context *cmd, lvmlock_t lock, size_t *mstats
                                return 0;
                        }
                }
-               lseek(_maps_fd, 0, SEEK_SET);
+               if (lseek(_maps_fd, 0, SEEK_SET))
+                       log_sys_error("lseek", _procselfmaps);
                for (len = 0 ; len < _maps_len; len += n) {
                        if (!(n = read(_maps_fd, _maps_buffer + len, _maps_len - len))) {
                                _maps_buffer[len] = '\0';
@@ -320,9 +359,16 @@ static void _unlock_mem(struct cmd_context *cmd)
                        log_sys_error("close", _procselfmaps);
                dm_free(_maps_buffer);
                _maps_buffer = NULL;
-               if (_mstats < unlock_mstats)
-                       log_error(INTERNAL_ERROR "Maps lock %ld < unlock %ld",
-                                 (long)_mstats, (long)unlock_mstats);
+               if (_mstats < unlock_mstats) {
+                       if ((_mstats + lvm_getpagesize()) < unlock_mstats)
+                               log_error(INTERNAL_ERROR
+                                         "Reserved memory (%ld) not enough: used %ld. Increase activation/reserved_memory?",
+                                         (long)_mstats, (long)unlock_mstats);
+                       else
+                               /* FIXME Believed due to incorrect use of yes_no_prompt while locks held */
+                               log_debug("Suppressed internal error: Maps lock %ld < unlock %ld, a one-page difference.",
+                                         (long)_mstats, (long)unlock_mstats);
+               }
        }
 
        if (setpriority(PRIO_PROCESS, 0, _priority))
@@ -333,46 +379,64 @@ static void _unlock_mem(struct cmd_context *cmd)
 
 static void _lock_mem_if_needed(struct cmd_context *cmd)
 {
-       if ((_memlock_count + _memlock_count_daemon) == 1)
+       log_debug("Lock:   Memlock counters: locked:%d critical:%d daemon:%d suspended:%d",
+                 _mem_locked, _critical_section, _memlock_count_daemon, dm_get_suspended_counter());
+       if (!_mem_locked &&
+           ((_critical_section + _memlock_count_daemon) == 1)) {
+               _mem_locked = 1;
                _lock_mem(cmd);
+       }
 }
 
 static void _unlock_mem_if_possible(struct cmd_context *cmd)
 {
-       if ((_memlock_count + _memlock_count_daemon) == 0)
+       log_debug("Unlock: Memlock counters: locked:%d critical:%d daemon:%d suspended:%d",
+                 _mem_locked, _critical_section, _memlock_count_daemon, dm_get_suspended_counter());
+       if (_mem_locked &&
+           !_critical_section &&
+           !_memlock_count_daemon) {
                _unlock_mem(cmd);
+               _mem_locked = 0;
+       }
 }
 
-void memlock_inc(struct cmd_context *cmd)
+void critical_section_inc(struct cmd_context *cmd, const char *reason)
 {
-       ++_memlock_count;
+       if (!_critical_section) {
+               _critical_section = 1;
+               log_debug("Entering critical section (%s).", reason);
+       }
+
        _lock_mem_if_needed(cmd);
-       log_debug("memlock_count inc to %d", _memlock_count);
 }
 
-void memlock_dec(struct cmd_context *cmd)
+void critical_section_dec(struct cmd_context *cmd, const char *reason)
 {
-       if (!_memlock_count)
-               log_error(INTERNAL_ERROR "_memlock_count has dropped below 0.");
-       --_memlock_count;
-       _unlock_mem_if_possible(cmd);
-       log_debug("memlock_count dec to %d", _memlock_count);
+       if (_critical_section && !dm_get_suspended_counter()) {
+               _critical_section = 0;
+               log_debug("Leaving critical section (%s).", reason);
+       }
+}
+
+int critical_section(void)
+{
+       return _critical_section;
 }
 
 /*
  * The memlock_*_daemon functions will force the mlockall() call that we need
  * to stay in memory, but they will have no effect on device scans (unlike
- * normal memlock_inc and memlock_dec). Memory is kept locked as long as either
- * of memlock or memlock_daemon is in effect.
+ * normal critical_section_inc/dec). Memory is kept locked as long as either
+ * of critical_section or memlock_daemon is in effect.
  */
 
 void memlock_inc_daemon(struct cmd_context *cmd)
 {
        ++_memlock_count_daemon;
-       if (_memlock_count_daemon == 1 && _memlock_count > 0)
-                log_error(INTERNAL_ERROR "_memlock_inc_daemon used after _memlock_inc.");
-       _lock_mem_if_needed(cmd);
+       if (_memlock_count_daemon == 1 && _critical_section > 0)
+                log_error(INTERNAL_ERROR "_memlock_inc_daemon used in critical section.");
        log_debug("memlock_count_daemon inc to %d", _memlock_count_daemon);
+       _lock_mem_if_needed(cmd);
 }
 
 void memlock_dec_daemon(struct cmd_context *cmd)
@@ -380,32 +444,35 @@ void memlock_dec_daemon(struct cmd_context *cmd)
        if (!_memlock_count_daemon)
                log_error(INTERNAL_ERROR "_memlock_count_daemon has dropped below 0.");
        --_memlock_count_daemon;
-       _unlock_mem_if_possible(cmd);
        log_debug("memlock_count_daemon dec to %d", _memlock_count_daemon);
-}
-
-/*
- * This disregards the daemon (dmeventd) locks, since we use memlock() to check
- * whether it is safe to run a device scan, which would normally coincide with
- * !memlock() -- but the daemon global memory lock breaks this assumption, so
- * we do not take those into account here.
- */
-int memlock(void)
-{
-       return _memlock_count;
+       _unlock_mem_if_possible(cmd);
 }
 
 void memlock_init(struct cmd_context *cmd)
 {
-       _size_stack = find_config_tree_int(cmd,
-                                     "activation/reserved_stack",
-                                     DEFAULT_RESERVED_STACK) * 1024;
+       /* When threaded, caller already limited stack size so just use the default. */
+       _size_stack = 1024ULL * (cmd->threaded ? DEFAULT_RESERVED_STACK :
+                                find_config_tree_int(cmd, "activation/reserved_stack",
+                                                     DEFAULT_RESERVED_STACK));
        _size_malloc_tmp = find_config_tree_int(cmd,
                                           "activation/reserved_memory",
-                                          DEFAULT_RESERVED_MEMORY) * 1024;
+                                          DEFAULT_RESERVED_MEMORY) * 1024ULL;
        _default_priority = find_config_tree_int(cmd,
                                            "activation/process_priority",
                                            DEFAULT_PROCESS_PRIORITY);
 }
 
+void memlock_reset(void)
+{
+       log_debug("memlock reset.");
+       _mem_locked = 0;
+       _critical_section = 0;
+       _memlock_count_daemon = 0;
+}
+
+void memlock_unlock(struct cmd_context *cmd)
+{
+       _unlock_mem_if_possible(cmd);
+}
+
 #endif
index fd19317ce9036fe1d75662eead75c7b3bef8f64a..aab9c859cfcdd9cd4655a7122f70d89405952c75 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.  
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
 
 struct cmd_context;
 
-void memlock_inc(struct cmd_context *cmd);
-void memlock_dec(struct cmd_context *cmd);
+/*
+ * Inside a critical section, memory is always locked.
+ *
+ * After leaving the critical section, memory stays locked until 
+ * memlock_unlock() is called.  This happens with
+ * sync_local_dev_names() and sync_dev_names().
+ *
+ * This allows critical sections to be entered and exited repeatedly without
+ * incurring the expense of locking memory every time.
+ *
+ * memlock_reset() is necessary to clear the state after forking (polldaemon).
+ */
+
+void critical_section_inc(struct cmd_context *cmd, const char *reason);
+void critical_section_dec(struct cmd_context *cmd, const char *reason);
+int critical_section(void);
 void memlock_inc_daemon(struct cmd_context *cmd);
 void memlock_dec_daemon(struct cmd_context *cmd);
-int memlock(void);
 void memlock_init(struct cmd_context *cmd);
+void memlock_reset(void);
+void memlock_unlock(struct cmd_context *cmd);
 
 #endif
diff --git a/lib/raid/.exported_symbols b/lib/raid/.exported_symbols
new file mode 100644 (file)
index 0000000..0d012d6
--- /dev/null
@@ -0,0 +1 @@
+init_multiple_segtypes
diff --git a/lib/raid/Makefile.in b/lib/raid/Makefile.in
new file mode 100644 (file)
index 0000000..73a1f80
--- /dev/null
@@ -0,0 +1,26 @@
+#
+# Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
+# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = @top_builddir@
+
+SOURCES = raid.c
+
+LIB_SHARED = liblvm2raid.$(LIB_SUFFIX)
+LIB_VERSION = $(LIB_VERSION_LVM)
+
+include $(top_builddir)/make.tmpl
+
+install: install_lvm2_plugin
diff --git a/lib/raid/raid.c b/lib/raid/raid.c
new file mode 100644 (file)
index 0000000..78fe074
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "lib.h"
+#include "toolcontext.h"
+#include "segtype.h"
+#include "display.h"
+#include "text_export.h"
+#include "text_import.h"
+#include "config.h"
+#include "str_list.h"
+#include "targets.h"
+#include "lvm-string.h"
+#include "activate.h"
+#include "metadata.h"
+#include "lv_alloc.h"
+#include "defaults.h"
+
+static const char *_raid_name(const struct lv_segment *seg)
+{
+       return seg->segtype->name;
+}
+
+static int _raid_text_import_area_count(const struct dm_config_node *sn,
+                                       uint32_t *area_count)
+{
+       if (!dm_config_get_uint32(sn, "device_count", area_count)) {
+               log_error("Couldn't read 'device_count' for "
+                         "segment '%s'.", dm_config_parent_name(sn));
+               return 0;
+       }
+       return 1;
+}
+
+static int _raid_text_import_areas(struct lv_segment *seg,
+                                  const struct dm_config_node *sn,
+                                  const struct dm_config_value *cv)
+{
+       unsigned int s;
+       struct logical_volume *lv1;
+       const char *seg_name = dm_config_parent_name(sn);
+
+       if (!seg->area_count) {
+               log_error("No areas found for segment %s", seg_name);
+               return 0;
+       }
+
+       for (s = 0; cv && s < seg->area_count; s++, cv = cv->next) {
+               if (cv->type != DM_CFG_STRING) {
+                       log_error("Bad volume name in areas array for segment %s.", seg_name);
+                       return 0;
+               }
+
+               if (!cv->next) {
+                       log_error("Missing data device in areas array for segment %s.", seg_name);
+                       return 0;
+               }
+
+               /* Metadata device comes first */
+               if (!(lv1 = find_lv(seg->lv->vg, cv->v.str))) {
+                       log_error("Couldn't find volume '%s' for segment '%s'.",
+                                 cv->v.str ? : "NULL", seg_name);
+                       return 0;
+               }
+               if (!set_lv_segment_area_lv(seg, s, lv1, 0, RAID_META))
+                               return_0;
+
+               /* Data device comes second */
+               cv = cv->next;
+               if (!(lv1 = find_lv(seg->lv->vg, cv->v.str))) {
+                       log_error("Couldn't find volume '%s' for segment '%s'.",
+                                 cv->v.str ? : "NULL", seg_name);
+                       return 0;
+               }
+               if (!set_lv_segment_area_lv(seg, s, lv1, 0, RAID_IMAGE))
+                               return_0;
+       }
+
+       /*
+        * Check we read the correct number of RAID data/meta pairs.
+        */
+       if (cv || (s < seg->area_count)) {
+               log_error("Incorrect number of areas in area array "
+                         "for segment '%s'.", seg_name);
+               return 0;
+       }
+
+       return 1;
+}
+
+static int _raid_text_import(struct lv_segment *seg,
+                            const struct dm_config_node *sn,
+                            struct dm_hash_table *pv_hash)
+{
+       const struct dm_config_value *cv;
+
+       if (dm_config_has_node(sn, "region_size")) {
+               if (!dm_config_get_uint32(sn, "region_size", &seg->region_size)) {
+                       log_error("Couldn't read 'region_size' for "
+                                 "segment %s of logical volume %s.",
+                                 dm_config_parent_name(sn), seg->lv->name);
+                       return 0;
+               }
+       }
+       if (dm_config_has_node(sn, "stripe_size")) {
+               if (!dm_config_get_uint32(sn, "stripe_size", &seg->stripe_size)) {
+                       log_error("Couldn't read 'stripe_size' for "
+                                 "segment %s of logical volume %s.",
+                                 dm_config_parent_name(sn), seg->lv->name);
+                       return 0;
+               }
+       }
+       if (!dm_config_get_list(sn, "raids", &cv)) {
+               log_error("Couldn't find RAID array for "
+                         "segment %s of logical volume %s.",
+                         dm_config_parent_name(sn), seg->lv->name);
+               return 0;
+       }
+
+       if (!_raid_text_import_areas(seg, sn, cv)) {
+               log_error("Failed to import RAID images");
+               return 0;
+       }
+
+       seg->status |= RAID;
+
+       return 1;
+}
+
+static int _raid_text_export(const struct lv_segment *seg, struct formatter *f)
+{
+       outf(f, "device_count = %u", seg->area_count);
+       if (seg->region_size)
+               outf(f, "region_size = %" PRIu32, seg->region_size);
+       if (seg->stripe_size)
+               outf(f, "stripe_size = %" PRIu32, seg->stripe_size);
+
+       return out_areas(f, seg, "raid");
+}
+
+static int _raid_add_target_line(struct dev_manager *dm __attribute__((unused)),
+                                struct dm_pool *mem __attribute__((unused)),
+                                struct cmd_context *cmd __attribute__((unused)),
+                                void **target_state __attribute__((unused)),
+                                struct lv_segment *seg,
+                                const struct lv_activate_opts *laopts __attribute__((unused)),
+                                struct dm_tree_node *node, uint64_t len,
+                                uint32_t *pvmove_mirror_count __attribute__((unused)))
+{
+       uint32_t s;
+       uint64_t flags = 0;
+       uint64_t rebuilds = 0;
+
+       if (!seg->area_count) {
+               log_error(INTERNAL_ERROR "_raid_add_target_line called "
+                         "with no areas for %s.", seg->lv->name);
+               return 0;
+       }
+
+       /*
+        * 64 device restriction imposed by kernel as well.  It is
+        * not strictly a userspace limitation.
+        */
+       if (seg->area_count > 64) {
+               log_error("Unable to handle more than 64 devices in a "
+                         "single RAID array");
+               return 0;
+       }
+
+       if (!seg->region_size) {
+               log_error("Missing region size for mirror segment.");
+               return 0;
+       }
+
+       for (s = 0; s < seg->area_count; s++)
+               if (seg_lv(seg, s)->status & LV_REBUILD)
+                       rebuilds |= 1 << s;
+
+       if (mirror_in_sync())
+               flags = DM_NOSYNC;
+
+       if (!dm_tree_node_add_raid_target(node, len, _raid_name(seg),
+                                         seg->region_size, seg->stripe_size,
+                                         rebuilds, flags))
+               return_0;
+
+       return add_areas_line(dm, seg, node, 0u, seg->area_count);
+}
+
+static int _raid_target_status_compatible(const char *type)
+{
+       return (strstr(type, "raid") != NULL);
+}
+
+static int _raid_target_percent(void **target_state,
+                               percent_t *percent,
+                               struct dm_pool *mem,
+                               struct cmd_context *cmd,
+                               struct lv_segment *seg, char *params,
+                               uint64_t *total_numerator,
+                               uint64_t *total_denominator)
+{
+       int i;
+       uint64_t numerator, denominator;
+       char *pos = params;
+       /*
+        * Status line:
+        *    <raid_type> <#devs> <status_chars> <synced>/<total>
+        * Example:
+        *    raid1 2 AA 1024000/1024000
+        */
+       for (i = 0; i < 3; i++) {
+               pos = strstr(pos, " ");
+               if (pos)
+                       pos++;
+               else
+                       break;
+       }
+       if (!pos || (sscanf(pos, "%" PRIu64 "/%" PRIu64 "%n",
+                           &numerator, &denominator, &i) != 2)) {
+               log_error("Failed to parse %s status fraction: %s",
+                         (seg) ? seg->segtype->name : "segment", params);
+               return 0;
+       }
+
+       *total_numerator += numerator;
+       *total_denominator += denominator;
+
+       if (seg)
+               seg->extents_copied = seg->area_len * numerator / denominator;
+
+       *percent = make_percent(numerator, denominator);
+
+       return 1;
+}
+
+
+static int _raid_target_present(struct cmd_context *cmd,
+                               const struct lv_segment *seg __attribute__((unused)),
+                               unsigned *attributes __attribute__((unused)))
+{
+       static int _raid_checked = 0;
+       static int _raid_present = 0;
+
+       if (!_raid_checked)
+               _raid_present = target_present(cmd, "raid", 1);
+
+       _raid_checked = 1;
+
+       return _raid_present;
+}
+
+static int _raid_modules_needed(struct dm_pool *mem,
+                               const struct lv_segment *seg __attribute__((unused)),
+                               struct dm_list *modules)
+{
+       if (!str_list_add(mem, modules, "raid")) {
+               log_error("raid module string list allocation failed");
+               return 0;
+       }
+
+       return 1;
+}
+
+static void _raid_destroy(struct segment_type *segtype)
+{
+       dm_free((void *) segtype);
+}
+
+#ifdef DEVMAPPER_SUPPORT
+#ifdef DMEVENTD
+static const char *_get_raid_dso_path(struct cmd_context *cmd)
+{
+       const char *config_str = find_config_tree_str(cmd, "dmeventd/raid_library",
+                                                     DEFAULT_DMEVENTD_RAID_LIB);
+       return get_monitor_dso_path(cmd, config_str);
+}
+
+static int _raid_target_monitored(struct lv_segment *seg, int *pending)
+{
+       struct cmd_context *cmd = seg->lv->vg->cmd;
+       const char *dso_path = _get_raid_dso_path(cmd);
+
+       return target_registered_with_dmeventd(cmd, dso_path, seg->lv, pending);
+}
+
+static int _raid_set_events(struct lv_segment *seg, int evmask, int set)
+{
+       struct cmd_context *cmd = seg->lv->vg->cmd;
+       const char *dso_path = _get_raid_dso_path(cmd);
+
+       return target_register_events(cmd, dso_path, seg->lv, evmask, set, 0);
+}
+
+static int _raid_target_monitor_events(struct lv_segment *seg, int events)
+{
+       return _raid_set_events(seg, events, 1);
+}
+
+static int _raid_target_unmonitor_events(struct lv_segment *seg, int events)
+{
+       return _raid_set_events(seg, events, 0);
+}
+#endif /* DEVMAPPER_SUPPORT */
+#endif /* DMEVENTD */
+static struct segtype_handler _raid_ops = {
+       .name = _raid_name,
+       .text_import_area_count = _raid_text_import_area_count,
+       .text_import = _raid_text_import,
+       .text_export = _raid_text_export,
+       .add_target_line = _raid_add_target_line,
+       .target_status_compatible = _raid_target_status_compatible,
+#ifdef DEVMAPPER_SUPPORT
+       .target_percent = _raid_target_percent,
+       .target_present = _raid_target_present,
+#  ifdef DMEVENTD
+       .target_monitored = _raid_target_monitored,
+       .target_monitor_events = _raid_target_monitor_events,
+       .target_unmonitor_events = _raid_target_unmonitor_events,
+#  endif        /* DMEVENTD */
+#endif
+       .modules_needed = _raid_modules_needed,
+       .destroy = _raid_destroy,
+};
+
+static struct segment_type *_init_raid_segtype(struct cmd_context *cmd,
+                                              const char *raid_type)
+{
+       struct segment_type *segtype = dm_zalloc(sizeof(*segtype));
+
+       if (!segtype) {
+               log_error("Failed to allocate memory for %s segtype",
+                         raid_type);
+               return NULL;
+       }
+       segtype->cmd = cmd;
+
+       segtype->flags = SEG_RAID;
+#ifdef DEVMAPPER_SUPPORT
+#ifdef DMEVENTD
+       if (_get_raid_dso_path(cmd))
+               segtype->flags |= SEG_MONITORED;
+#endif
+#endif
+       segtype->parity_devs = strstr(raid_type, "raid6") ? 2 : 1;
+
+       segtype->ops = &_raid_ops;
+       segtype->name = raid_type;
+
+       segtype->private = NULL;
+
+       log_very_verbose("Initialised segtype: %s", segtype->name);
+
+       return segtype;
+}
+
+static struct segment_type *_init_raid1_segtype(struct cmd_context *cmd)
+{
+       struct segment_type *segtype;
+
+       segtype = _init_raid_segtype(cmd, "raid1");
+       if (!segtype)
+               return NULL;
+
+       segtype->flags |= SEG_AREAS_MIRRORED;
+       segtype->parity_devs = 0;
+
+       return segtype;
+}
+
+static struct segment_type *_init_raid10_segtype(struct cmd_context *cmd)
+{
+       struct segment_type *segtype;
+
+       segtype = _init_raid_segtype(cmd, "raid10");
+       if (!segtype)
+               return NULL;
+
+       segtype->flags |= SEG_AREAS_MIRRORED;
+       segtype->parity_devs = 0;
+
+       return segtype;
+}
+
+static struct segment_type *_init_raid4_segtype(struct cmd_context *cmd)
+{
+       return _init_raid_segtype(cmd, "raid4");
+}
+
+static struct segment_type *_init_raid5_segtype(struct cmd_context *cmd)
+{
+       return _init_raid_segtype(cmd, "raid5");
+}
+
+static struct segment_type *_init_raid5_la_segtype(struct cmd_context *cmd)
+{
+       return _init_raid_segtype(cmd, "raid5_la");
+}
+
+static struct segment_type *_init_raid5_ra_segtype(struct cmd_context *cmd)
+{
+       return _init_raid_segtype(cmd, "raid5_ra");
+}
+
+static struct segment_type *_init_raid5_ls_segtype(struct cmd_context *cmd)
+{
+       return _init_raid_segtype(cmd, "raid5_ls");
+}
+
+static struct segment_type *_init_raid5_rs_segtype(struct cmd_context *cmd)
+{
+       return _init_raid_segtype(cmd, "raid5_rs");
+}
+
+static struct segment_type *_init_raid6_segtype(struct cmd_context *cmd)
+{
+       return _init_raid_segtype(cmd, "raid6");
+}
+
+static struct segment_type *_init_raid6_zr_segtype(struct cmd_context *cmd)
+{
+       return _init_raid_segtype(cmd, "raid6_zr");
+}
+
+static struct segment_type *_init_raid6_nr_segtype(struct cmd_context *cmd)
+{
+       return _init_raid_segtype(cmd, "raid6_nr");
+}
+
+static struct segment_type *_init_raid6_nc_segtype(struct cmd_context *cmd)
+{
+       return _init_raid_segtype(cmd, "raid6_nc");
+}
+
+#ifdef RAID_INTERNAL /* Shared */
+int init_raid_segtypes(struct cmd_context *cmd, struct segtype_library *seglib)
+#else
+int init_multiple_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
+
+int init_multiple_segtypes(struct cmd_context *cmd, struct segtype_library *seglib)
+#endif
+{
+       struct segment_type *segtype;
+       unsigned i = 0;
+       struct segment_type *(*raid_segtype_fn[])(struct cmd_context *) =  {
+               _init_raid1_segtype,
+               _init_raid10_segtype,
+               _init_raid4_segtype,
+               _init_raid5_segtype,
+               _init_raid5_la_segtype,
+               _init_raid5_ra_segtype,
+               _init_raid5_ls_segtype,
+               _init_raid5_rs_segtype,
+               _init_raid6_segtype,
+               _init_raid6_zr_segtype,
+               _init_raid6_nr_segtype,
+               _init_raid6_nc_segtype,
+               NULL,
+       };
+
+       do {
+               if ((segtype = raid_segtype_fn[i](cmd)) &&
+                   !lvm_register_segtype(seglib, segtype))
+                       /* segtype is already destroyed */
+                       return_0;
+       } while (raid_segtype_fn[++i]);
+
+       return 1;
+}
index 26a5cf1c04eaea7da04e8592933c78dcca2f518d..76bdbcaedba4427f68709937ff787b3628a20372 100644 (file)
 #include "metadata.h"
 #include "segtype.h"
 #include "text_export.h"
-#include "text_import.h"
-#include "config.h"
 #include "activate.h"
 #include "str_list.h"
 #ifdef DMEVENTD
-#  include "sharedlib.h"
 #  include "libdevmapper-event.h"
 #endif
 
@@ -36,7 +33,7 @@
  */
 #define SEG_LOG_ERROR(t, p...) \
        log_error(t " segment %s of logical volume %s.", ## p, \
-                 config_parent_name(sn), seg->lv->name), 0;
+                 dm_config_parent_name(sn), seg->lv->name), 0;
 
 
 /*
@@ -58,24 +55,24 @@ static void _replicator_display(const struct lv_segment *seg)
                log_print("  Replicator volume\t%s", seg->rlog_lv->name);
 }
 
-/* Wrapper for get_config_uint32() with default value */
-static uint32_t _get_config_uint32(const struct config_node *cn,
+/* Wrapper for dm_config_get_uint32() with default value */
+static uint32_t _get_config_uint32(const struct dm_config_node *cn,
                                   const char *path,
                                   uint32_t def)
 {
        uint32_t t;
 
-       return get_config_uint32(cn, path, &t) ? t : def;
+       return dm_config_get_uint32(cn, path, &t) ? t : def;
 }
 
-/* Wrapper for get_config_uint64() with default value */
-static uint64_t _get_config_uint64(const struct config_node *cn,
+/* Wrapper for dm_config_get_uint64() with default value */
+static uint64_t _get_config_uint64(const struct dm_config_node *cn,
                                   const char *path,
                                   uint64_t def)
 {
        uint64_t t;
 
-       return get_config_uint64(cn, path, &t) ? t : def;
+       return dm_config_get_uint64(cn, path, &t) ? t : def;
 }
 
 
@@ -86,13 +83,13 @@ static const char _state_txt[NUM_REPLICATOR_STATE][8] = {
 };
 
 /* Parse state string */
-static replicator_state_t _get_state(const struct config_node *sn,
+static replicator_state_t _get_state(const struct dm_config_node *sn,
                                     const char *path, replicator_state_t def)
 {
        const char *str;
        unsigned i;
 
-       if (get_config_str(sn, path, &str)) {
+       if (dm_config_get_str(sn, path, &str)) {
                for (i = 0; i < sizeof(_state_txt)/sizeof(_state_txt[0]); ++i)
                        if (strcasecmp(str, _state_txt[i]) == 0)
                                return (replicator_state_t) i;
@@ -115,13 +112,13 @@ static const char _op_mode_txt[NUM_DM_REPLICATOR_MODES][8] = {
 
 
 /* Parse action string */
-static dm_replicator_mode_t _get_op_mode(const struct config_node *sn,
+static dm_replicator_mode_t _get_op_mode(const struct dm_config_node *sn,
                                         const char *path, dm_replicator_mode_t def)
 {
        const char *str;
        unsigned i;
 
-       if (get_config_str(sn, path, &str)) {
+       if (dm_config_get_str(sn, path, &str)) {
                for (i = 0; i < sizeof(_op_mode_txt)/sizeof(_op_mode_txt[0]); ++i)
                        if (strcasecmp(str, _op_mode_txt[i]) == 0) {
                                log_very_verbose("Setting %s to %s",
@@ -162,16 +159,16 @@ static struct replicator_site *_get_site(struct logical_volume *replicator,
 /* Parse replicator site element */
 static int _add_site(struct lv_segment *seg,
                     const char *key,
-                    const struct config_node *sn)
+                    const struct dm_config_node *sn)
 {
        struct dm_pool *mem = seg->lv->vg->vgmem;
-       const struct config_node *cn;
+       const struct dm_config_node *cn;
        struct replicator_site *rsite;
 
        if (!(rsite = _get_site(seg->lv, key)))
                return_0;
 
-       if (!find_config_node(sn, "site_index"))
+       if (!dm_config_find_node(sn, "site_index"))
                return SEG_LOG_ERROR("Mandatory site_index is missing for");
 
        rsite->state = _get_state(sn, "state", REPLICATOR_STATE_PASSIVE);
@@ -204,8 +201,8 @@ static int _add_site(struct lv_segment *seg,
                                              rsite->op_mode);
        }
 
-       if ((cn = find_config_node(sn, "volume_group"))) {
-               if (!cn->v || cn->v->type != CFG_STRING)
+       if ((cn = dm_config_find_node(sn, "volume_group"))) {
+               if (!cn->v || cn->v->type != DM_CFG_STRING)
                        return SEG_LOG_ERROR("volume_group must be a string in");
 
                if (!(rsite->vg_name = dm_pool_strdup(mem, cn->v->v.str)))
@@ -220,25 +217,25 @@ static int _add_site(struct lv_segment *seg,
 
 /* Import replicator segment */
 static int _replicator_text_import(struct lv_segment *seg,
-                                  const struct config_node *sn,
+                                  const struct dm_config_node *sn,
                                   struct dm_hash_table *pv_hash __attribute__((unused)))
 {
-       const struct config_node *cn;
+       const struct dm_config_node *cn;
        struct logical_volume *rlog_lv;
 
        if (!replicator_add_replicator_dev(seg->lv, NULL))
                return_0;
 
-       if (!(cn = find_config_node(sn, "replicator_log")) ||
-           !cn->v || cn->v->type != CFG_STRING)
+       if (!(cn = dm_config_find_node(sn, "replicator_log")) ||
+           !cn->v || cn->v->type != DM_CFG_STRING)
                return SEG_LOG_ERROR("Replicator log type must be a string in");
 
        if (!(rlog_lv = find_lv(seg->lv->vg, cn->v->v.str)))
                return SEG_LOG_ERROR("Unknown replicator log %s in",
                                     cn->v->v.str);
 
-       if (!(cn = find_config_node(sn, "replicator_log_type")) ||
-           !cn->v || cn->v->type != CFG_STRING)
+       if (!(cn = dm_config_find_node(sn, "replicator_log_type")) ||
+           !cn->v || cn->v->type != DM_CFG_STRING)
                return SEG_LOG_ERROR("Replicator log's type must be a string in");
        if (strcasecmp(cn->v->v.str, "ringbuffer"))
                return SEG_LOG_ERROR("Only ringbuffer replicator log type is supported in");
@@ -327,6 +324,7 @@ static int _replicator_add_target_line(struct dev_manager *dm,
                                       struct cmd_context *cmd,
                                       void **target_state,
                                       struct lv_segment *seg,
+                                      const struct lv_activate_opts *laopts,
                                       struct dm_tree_node *node,
                                       uint64_t len,
                                       uint32_t *pvmove_mirror_count)
@@ -442,7 +440,7 @@ static void _replicator_dev_display(const struct lv_segment *seg)
 
 static int _add_device(struct lv_segment *seg,
                       const char *site_name,
-                      const struct config_node *sn,
+                      const struct dm_config_node *sn,
                       uint64_t devidx)
 {
        struct dm_pool *mem = seg->lv->vg->vgmem;
@@ -452,19 +450,19 @@ static int _add_device(struct lv_segment *seg,
        struct replicator_device *rdev;
        const char *dev_str = NULL;
        const char *slog_str = NULL;
-       const struct config_node *cn;
+       const struct dm_config_node *cn;
 
        dm_list_iterate_items(rdev, &rsite->rdevices)
                if (rdev->replicator_dev == seg)
                        return SEG_LOG_ERROR("Duplicate site found in");
 
-       if ((cn = find_config_node(sn, "sync_log"))) {
+       if ((cn = dm_config_find_node(sn, "sync_log"))) {
                if (!cn->v || !cn->v->v.str)
                        return SEG_LOG_ERROR("Sync log must be a string in");
                slog_str = cn->v->v.str;
        }
 
-       if (!(cn = find_config_node(sn, "logical_volume")) ||
+       if (!(cn = dm_config_find_node(sn, "logical_volume")) ||
            !cn->v || !cn->v->v.str)
                return SEG_LOG_ERROR("Logical volume must be a string in");
 
@@ -519,14 +517,14 @@ static int _add_device(struct lv_segment *seg,
 
 /* Import replicator segment */
 static int _replicator_dev_text_import(struct lv_segment *seg,
-                                      const struct config_node *sn,
+                                      const struct dm_config_node *sn,
                                       struct dm_hash_table *pv_hash __attribute__((unused)))
 {
-       const struct config_node *cn;
+       const struct dm_config_node *cn;
        struct logical_volume *replicator;
        uint64_t devidx;
 
-       if (!(cn = find_config_node(sn, "replicator")))
+       if (!(cn = dm_config_find_node(sn, "replicator")))
                return SEG_LOG_ERROR("Replicator is missing for");
 
        if (!cn->v || !cn->v->v.str)
@@ -541,8 +539,8 @@ static int _replicator_dev_text_import(struct lv_segment *seg,
        log_very_verbose("replicator=%s", replicator->name);
 
        /* Mandatory */
-       if (!find_config_node(sn, "device_index") ||
-           !get_config_uint64(sn, "device_index", &devidx))
+       if (!dm_config_find_node(sn, "device_index") ||
+           !dm_config_get_uint64(sn, "device_index", &devidx))
                return SEG_LOG_ERROR("Could not read 'device_index' for");
 
        /* Read devices from sites */
@@ -609,6 +607,7 @@ static int _replicator_dev_add_target_line(struct dev_manager *dm,
                                           struct cmd_context *cmd,
                                           void **target_state,
                                           struct lv_segment *seg,
+                                          const struct lv_activate_opts *laopts,
                                           struct dm_tree_node *node,
                                           uint64_t len,
                                           uint32_t *pvmove_mirror_count)
@@ -623,7 +622,9 @@ static int _replicator_dev_add_target_line(struct dev_manager *dm,
                /* Create passive linear mapping */
                log_very_verbose("Inactive replicator %s using %s.",
                                 seg->lv->name, seg->lv->rdevice->lv->name);
-               if (!dm_tree_node_add_linear_target(node, seg->lv->size))
+               if (!add_linear_area_to_dtree(node, seg->lv->size, seg->lv->vg->extent_size,
+                                             cmd->use_linear_target,
+                                             seg->lv->vg->name, seg->lv->name))
                        return_0;
                if (!(rdev_dlid = build_dm_uuid(mem, seg->lv->rdevice->lv->lvid.s, NULL)))
                        return_0;
@@ -752,15 +753,15 @@ static struct segtype_handler _replicator_dev_ops = {
 };
 
 #ifdef REPLICATOR_INTERNAL
-int init_replicator_segtype(struct segtype_library *seglib)
+int init_replicator_segtype(struct cmd_context *cmd, struct segtype_library *seglib)
 #else /* Shared */
-int init_multiple_segtype(struct segtype_library *seglib);
-int init_multiple_segtype(struct segtype_library *seglib)
+int init_multiple_segtype(struct cmd_context *cmd, struct segtype_library *seglib);
+int init_multiple_segtype(struct cmd_context *cmd, struct segtype_library *seglib)
 #endif
 {
        struct segment_type *segtype;
 
-       if (!(segtype = dm_malloc(sizeof(*segtype))))
+       if (!(segtype = dm_zalloc(sizeof(*segtype))))
                return_0;
 
        segtype->ops = &_replicator_ops;
@@ -769,11 +770,12 @@ int init_multiple_segtype(struct segtype_library *seglib)
        segtype->flags = SEG_REPLICATOR;
 
        if (!lvm_register_segtype(seglib, segtype))
+               /* segtype is already destroyed */
                return_0;
 
        log_very_verbose("Initialised segtype: " REPLICATOR_MODULE);
 
-       if (!(segtype = dm_malloc(sizeof(*segtype))))
+       if (!(segtype = dm_zalloc(sizeof(*segtype))))
                return_0;
 
        segtype->ops = &_replicator_dev_ops;
@@ -782,6 +784,7 @@ int init_multiple_segtype(struct segtype_library *seglib)
        segtype->flags = SEG_REPLICATOR_DEV;
 
        if (!lvm_register_segtype(seglib, segtype))
+               /* segtype is already destroyed */
                return_0;
 
        log_very_verbose("Initialised segtype: " REPLICATOR_DEV_MODULE);
index acc232f28b07c8505afc2f647357281bacbdec10..6299a2bb545f1548c27d5a112cb38a4e607f476f 100644 (file)
@@ -71,15 +71,23 @@ FIELD(LVS, lv, STR, "KMaj", lvid, 4, lvkmaj, lv_kernel_major, "Currently assigne
 FIELD(LVS, lv, STR, "KMin", lvid, 4, lvkmin, lv_kernel_minor, "Currently assigned minor number or -1 if LV is not active.", 0)
 FIELD(LVS, lv, NUM, "KRahead", lvid, 7, lvkreadahead, lv_kernel_read_ahead, "Currently-in-use read ahead setting in current units.", 0)
 FIELD(LVS, lv, NUM, "LSize", size, 5, size64, lv_size, "Size of LV in current units.", 0)
+FIELD(LVS, lv, NUM, "MSize", lvid, 6, lvmetadatasize, lv_metadata_size, "For thin pools, the size of the LV that holds the metadata.", 0)
 FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, seg_count, "Number of segments in LV.", 0)
 FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, origin, "For snapshots, the origin device of this LV.", 0)
 FIELD(LVS, lv, NUM, "OSize", lvid, 5, originsize, origin_size, "For snapshots, the size of the origin device of this LV.", 0)
+FIELD(LVS, lv, NUM, "Data%", lvid, 6, datapercent, data_percent, "For snapshot and thin pools and volumes, the percentage full if LV is active.", 0)
 FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, snap_percent, "For snapshots, the percentage full if LV is active.", 0)
+FIELD(LVS, lv, NUM, "Meta%", lvid, 6, metadatapercent, metadata_percent, "For thin pools, the percentage of metadata full if LV is active.", 0)
 FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, copy_percent, "For mirrors and pvmove, current percentage in-sync.", 0)
 FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, move_pv, "For pvmove, Source PV of temporary LV created by pvmove.", 0)
 FIELD(LVS, lv, STR, "Convert", lvid, 7, convertlv, convert_lv, "For lvconvert, Name of temporary LV created by lvconvert.", 0)
-FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, lv_tags, "Tags, if any.", 0)
 FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, mirror_log, "For mirrors, the LV holding the synchronisation log.", 0)
+FIELD(LVS, lv, STR, "Data", lvid, 4, datalv, data_lv, "For thin pools, the LV holding the associated data.", 0)
+FIELD(LVS, lv, STR, "Meta", lvid, 4, metadatalv, metadata_lv, "For thin pools, the LV holding the associated metadata.", 0)
+FIELD(LVS, lv, STR, "Pool", lvid, 4, poollv, pool_lv, "For thin volumes, the thin pool LV for this volume.", 0)
+FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, lv_tags, "Tags, if any.", 0)
+FIELD(LVS, lv, STR, "Time", lvid, 26, lvtime, lv_time, "Creation time of the LV, if known", 0)
+FIELD(LVS, lv, STR, "Host", lvid, 10, lvhost, lv_host, "Creation host of the LV, if known.", 0)
 FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, modules, "Kernel device-mapper modules required for this LV.", 0)
 
 FIELD(LABEL, pv, STR, "Fmt", id, 3, pvfmt, pv_fmt, "Type of metadata.", 0)
@@ -131,6 +139,10 @@ FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, regionsize, "For mirrors
 FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, region_size, "For mirrors, the unit of data copied when synchronising devices.", 0)
 FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, chunksize, "For snapshots, the unit of data used when tracking changes.", 0)
 FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, chunk_size, "For snapshots, the unit of data used when tracking changes.", 0)
+FIELD(SEGS, seg, NUM, "#Thins", list, 4, thincount, thin_count, "For thin pools, the number of thin volumes in this pool.", 0)
+FIELD(SEGS, seg, NUM, "Discards", list, 8, discards, discards, "For thin pools, how discards are handled.", 0)
+FIELD(SEGS, seg, NUM, "Zero", list, 4, thinzero, zero, "For thin pools, if zeroing is enabled.", 0)
+FIELD(SEGS, seg, NUM, "TransId", list, 4, transactionid, transaction_id, "For thin pools, the transaction id.", 0)
 FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, seg_start, "Offset within the LV to the start of the segment in current units.", 0)
 FIELD(SEGS, seg, NUM, "Start", list, 5, segstartpe, seg_start_pe, "Offset within the LV to the start of the segment in physical extents.", 0)
 FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, seg_size, "Size of segment in current units.", 0)
index 0b4929aa61702a01651c33e2697cb2e0d5afb109..c4f6ab985689fa76f0d7bbf23302a997ecd3f8ec 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2010-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -87,15 +87,39 @@ static int _not_implemented_set(void *obj, struct lvm_property_type *prop)
 }
 
 static percent_t _copy_percent(const struct logical_volume *lv) {
-    percent_t perc;
-    lv_mirror_percent(lv->vg->cmd, (struct logical_volume *) lv, 0, &perc, NULL);
-    return perc;
+       percent_t perc;
+       if (!lv_mirror_percent(lv->vg->cmd, lv, 0, &perc, NULL))
+               perc = PERCENT_INVALID;
+       return perc;
 }
 
 static percent_t _snap_percent(const struct logical_volume *lv) {
-    percent_t perc;
-    lv_snapshot_percent(lv, &perc);
-    return perc;
+       percent_t perc;
+
+       if (!lv_is_cow(lv) || !lv_snapshot_percent(lv, &perc))
+               perc = PERCENT_INVALID;
+
+       return perc;
+}
+
+static percent_t _data_percent(const struct logical_volume *lv)
+{
+       percent_t perc;
+
+       if (lv_is_cow(lv))
+               return _snap_percent(lv);
+
+       if (lv_is_thin_volume(lv))
+               return lv_thin_percent(lv, 0, &perc) ? perc : PERCENT_INVALID;
+
+       return lv_thin_pool_percent(lv, 0, &perc) ? perc : PERCENT_INVALID;
+}
+
+static percent_t _metadata_percent(const struct logical_volume *lv)
+{
+       percent_t perc;
+
+       return lv_thin_pool_percent(lv, 1, &perc) ? perc : PERCENT_INVALID;
 }
 
 /* PV */
@@ -175,6 +199,22 @@ GET_LV_STR_PROPERTY_FN(mirror_log, lv_mirror_log_dup(lv->vg->vgmem, lv))
 #define _mirror_log_set _not_implemented_set
 GET_LV_STR_PROPERTY_FN(modules, lv_modules_dup(lv->vg->vgmem, lv))
 #define _modules_set _not_implemented_set
+GET_LV_STR_PROPERTY_FN(data_lv, lv_data_lv_dup(lv->vg->vgmem, lv))
+#define _data_lv_set _not_implemented_set
+GET_LV_STR_PROPERTY_FN(metadata_lv, lv_metadata_lv_dup(lv->vg->vgmem, lv))
+#define _metadata_lv_set _not_implemented_set
+GET_LV_STR_PROPERTY_FN(pool_lv, lv_pool_lv_dup(lv->vg->vgmem, lv))
+#define _pool_lv_set _not_implemented_set
+GET_LV_NUM_PROPERTY_FN(data_percent, _data_percent(lv))
+#define _data_percent_set _not_implemented_set
+GET_LV_NUM_PROPERTY_FN(metadata_percent, _metadata_percent(lv))
+#define _metadata_percent_set _not_implemented_set
+GET_LV_NUM_PROPERTY_FN(lv_metadata_size, lv_metadata_size(lv) * SECTOR_SIZE)
+#define _lv_metadata_size_set _not_implemented_set
+GET_LV_STR_PROPERTY_FN(lv_time, lv_time_dup(lv->vg->vgmem, lv))
+#define _lv_time_set _not_implemented_set
+GET_LV_STR_PROPERTY_FN(lv_host, lv_host_dup(lv->vg->vgmem, lv))
+#define _lv_host_set _not_implemented_set
 
 /* VG */
 GET_VG_STR_PROPERTY_FN(vg_fmt, vg_fmt_dup(vg))
@@ -223,7 +263,7 @@ GET_VG_NUM_PROPERTY_FN(vg_mda_copies, (vg_mda_copies(vg)))
 SET_VG_NUM_PROPERTY_FN(vg_mda_copies, vg_set_mda_copies)
 
 /* LVSEG */
-GET_LVSEG_STR_PROPERTY_FN(segtype, lvseg_segtype_dup(lvseg))
+GET_LVSEG_STR_PROPERTY_FN(segtype, lvseg_segtype_dup(lvseg->lv->vg->vgmem, lvseg))
 #define _segtype_set _not_implemented_set
 GET_LVSEG_NUM_PROPERTY_FN(stripes, lvseg->area_count)
 #define _stripes_set _not_implemented_set
@@ -239,6 +279,14 @@ GET_LVSEG_NUM_PROPERTY_FN(chunksize, lvseg_chunksize(lvseg))
 #define _chunksize_set _not_implemented_set
 GET_LVSEG_NUM_PROPERTY_FN(chunk_size, lvseg_chunksize(lvseg))
 #define _chunk_size_set _not_implemented_set
+GET_LVSEG_NUM_PROPERTY_FN(thin_count, dm_list_size(&lvseg->lv->segs_using_this_lv))
+#define _thin_count_set _not_implemented_set
+GET_LVSEG_NUM_PROPERTY_FN(zero, lvseg->zero_new_blocks)
+#define _zero_set _not_implemented_set
+GET_LVSEG_NUM_PROPERTY_FN(transaction_id, lvseg->transaction_id)
+#define _transaction_id_set _not_implemented_set
+GET_LVSEG_NUM_PROPERTY_FN(discards, lvseg->discards)
+#define _discards_set _not_implemented_set
 GET_LVSEG_NUM_PROPERTY_FN(seg_start, lvseg_start(lvseg))
 #define _seg_start_set _not_implemented_set
 GET_LVSEG_NUM_PROPERTY_FN(seg_start_pe, lvseg->le)
@@ -247,9 +295,10 @@ GET_LVSEG_NUM_PROPERTY_FN(seg_size, (SECTOR_SIZE * lvseg_size(lvseg)))
 #define _seg_size_set _not_implemented_set
 GET_LVSEG_STR_PROPERTY_FN(seg_tags, lvseg_tags_dup(lvseg))
 #define _seg_tags_set _not_implemented_set
-#define _seg_pe_ranges_get _not_implemented_get
+GET_LVSEG_STR_PROPERTY_FN(seg_pe_ranges,
+                         lvseg_seg_pe_ranges(lvseg->lv->vg->vgmem, lvseg))
 #define _seg_pe_ranges_set _not_implemented_set
-#define _devices_get _not_implemented_get
+GET_LVSEG_STR_PROPERTY_FN(devices, lvseg_devices(lvseg->lv->vg->vgmem, lvseg))
 #define _devices_set _not_implemented_set
 
 
@@ -276,7 +325,7 @@ struct lvm_property_type _properties[] = {
 
 
 static int _get_property(const void *obj, struct lvm_property_type *prop,
-                        report_type_t type)
+                        unsigned type)
 {
        struct lvm_property_type *p;
 
@@ -304,7 +353,7 @@ static int _get_property(const void *obj, struct lvm_property_type *prop,
 }
 
 static int _set_property(void *obj, struct lvm_property_type *prop,
-                        report_type_t type)
+                        unsigned type)
 {
        struct lvm_property_type *p;
 
index f363362c7ab81b90cce1028ddcf63f6c5138634e..aefd3f589a49f64d148036b28f2d450b1d88d61b 100644 (file)
@@ -20,7 +20,7 @@
 #include "report.h"
 
 struct lvm_property_type {
-       report_type_t type;
+       unsigned type;
        const char *id;
        unsigned is_settable:1;
        unsigned is_string:1;
index 136ad4c53db2ad9a4f94301de9aab3232a7e3cd4..eeca282c9be5a77a7d413c31563f41e4cbd7d17a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -21,7 +21,6 @@
 #include "display.h"
 #include "activate.h"
 #include "segtype.h"
-#include "str_list.h"
 #include "lvmcache.h"
 
 #include <stddef.h> /* offsetof() */
@@ -44,7 +43,7 @@ static int _string_disp(struct dm_report *rh, struct dm_pool *mem __attribute__(
                        struct dm_report_field *field,
                        const void *data, void *private __attribute__((unused)))
 {
-       return dm_report_field_string(rh, field, (const char **) data);
+       return dm_report_field_string(rh, field, (const char * const *) data);
 }
 
 static int _dev_name_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
@@ -56,93 +55,30 @@ static int _dev_name_disp(struct dm_report *rh, struct dm_pool *mem __attribute_
        return dm_report_field_string(rh, field, &name);
 }
 
-static int _format_pvsegs(struct dm_pool *mem, struct dm_report_field *field,
-                         const void *data, int range_format)
+static int _devices_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
+                        struct dm_report_field *field,
+                        const void *data, void *private __attribute__((unused)))
 {
-       const struct lv_segment *seg = (const struct lv_segment *) data;
-       unsigned int s;
-       const char *name = NULL;
-       uint32_t extent = 0;
-       char extent_str[32];
-
-       if (!dm_pool_begin_object(mem, 256)) {
-               log_error("dm_pool_begin_object failed");
-               return 0;
-       }
-
-       for (s = 0; s < seg->area_count; s++) {
-               switch (seg_type(seg, s)) {
-               case AREA_LV:
-                       name = seg_lv(seg, s)->name;
-                       extent = seg_le(seg, s);
-                       break;
-               case AREA_PV:
-                       name = dev_name(seg_dev(seg, s));
-                       extent = seg_pe(seg, s);
-                       break;
-               case AREA_UNASSIGNED:
-                       name = "unassigned";
-                       extent = 0;
-               }
-
-               if (!dm_pool_grow_object(mem, name, strlen(name))) {
-                       log_error("dm_pool_grow_object failed");
-                       return 0;
-               }
-
-               if (dm_snprintf(extent_str, sizeof(extent_str),
-                               "%s%" PRIu32 "%s",
-                               range_format ? ":" : "(", extent,
-                               range_format ? "-"  : ")") < 0) {
-                       log_error("Extent number dm_snprintf failed");
-                       return 0;
-               }
-               if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) {
-                       log_error("dm_pool_grow_object failed");
-                       return 0;
-               }
-
-               if (range_format) {
-                       if (dm_snprintf(extent_str, sizeof(extent_str),
-                                       "%" PRIu32, extent + seg->area_len - 1) < 0) {
-                               log_error("Extent number dm_snprintf failed");
-                               return 0;
-                       }
-                       if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) {
-                               log_error("dm_pool_grow_object failed");
-                               return 0;
-                       }
-               }
-
-               if ((s != seg->area_count - 1) &&
-                   !dm_pool_grow_object(mem, range_format ? " " : ",", 1)) {
-                       log_error("dm_pool_grow_object failed");
-                       return 0;
-               }
-       }
-
-       if (!dm_pool_grow_object(mem, "\0", 1)) {
-               log_error("dm_pool_grow_object failed");
+       char *str;
+       if (!(str = lvseg_devices(mem, (const struct lv_segment *) data)))
                return 0;
-       }
 
-       dm_report_field_set_value(field, dm_pool_end_object(mem), NULL);
+       dm_report_field_set_value(field, str, NULL);
 
        return 1;
 }
 
-static int _devices_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
-                        struct dm_report_field *field,
-                        const void *data, void *private __attribute__((unused)))
-{
-       return _format_pvsegs(mem, field, data, 0);
-}
-
 static int _peranges_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
                          struct dm_report_field *field,
                          const void *data, void *private __attribute__((unused)))
 {
-       return _format_pvsegs(mem, field, data, 1);
+       char *str;
+       if (!(str = lvseg_seg_pe_ranges(mem, (const struct lv_segment *) data)))
+               return 0;
+
+       dm_report_field_set_value(field, str, NULL);
+
+       return 1;
 }
 
 static int _tags_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
@@ -278,9 +214,13 @@ static int _segtype_disp(struct dm_report *rh __attribute__((unused)),
                         const void *data, void *private __attribute__((unused)))
 {
        const struct lv_segment *seg = (const struct lv_segment *) data;
-
        char *name;
-       name = lvseg_segtype_dup(seg);
+
+       if (!(name = lvseg_segtype_dup(mem, seg))) {
+               log_error("Failed to get segtype.");
+               return 0;
+       }
+
        dm_report_field_set_value(field, name, NULL);
        return 1;
 }
@@ -307,10 +247,8 @@ static int _lvname_disp(struct dm_report *rh, struct dm_pool *mem,
        char *repstr, *lvname;
        size_t len;
 
-       if (lv_is_visible(lv)) {
-               repstr = lv->name;
-               return dm_report_field_string(rh, field, (const char **) &repstr);
-       }
+       if (lv_is_visible(lv))
+               return dm_report_field_string(rh, field, &lv->name);
 
        len = strlen(lv->name) + 3;
        if (!(repstr = dm_pool_zalloc(mem, len))) {
@@ -333,6 +271,51 @@ static int _lvname_disp(struct dm_report *rh, struct dm_pool *mem,
        return 1;
 }
 
+static int _datalv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
+                       struct dm_report_field *field,
+                       const void *data, void *private __attribute__((unused)))
+{
+       const struct logical_volume *lv = (const struct logical_volume *) data;
+
+       if (lv_is_thin_pool(lv))
+               return _lvname_disp(rh, mem, field,
+                                   seg_lv(first_seg(lv), 0), private);
+
+       dm_report_field_set_value(field, "", NULL);
+       return 1;
+}
+
+static int _metadatalv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
+                           struct dm_report_field *field,
+                           const void *data, void *private __attribute__((unused)))
+{
+       const struct logical_volume *lv = (const struct logical_volume *) data;
+
+       if (lv_is_thin_pool(lv))
+               return _lvname_disp(rh, mem, field,
+                                   first_seg(lv)->metadata_lv, private);
+
+       dm_report_field_set_value(field, "", NULL);
+       return 1;
+}
+
+static int _poollv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
+                       struct dm_report_field *field,
+                       const void *data, void *private __attribute__((unused)))
+{
+       const struct logical_volume *lv = (const struct logical_volume *) data;
+       struct lv_segment *seg;
+
+       if (lv_is_thin_volume(lv))
+               dm_list_iterate_items(seg, &lv->segments)
+                       if (seg_is_thin_volume(seg))
+                               return _lvname_disp(rh, mem, field,
+                                                   seg->pool_lv, private);
+
+       dm_report_field_set_value(field, "", NULL);
+       return 1;
+}
+
 static int _lvpath_disp(struct dm_report *rh, struct dm_pool *mem,
                        struct dm_report_field *field,
                        const void *data, void *private __attribute__((unused)))
@@ -357,6 +340,9 @@ static int _origin_disp(struct dm_report *rh, struct dm_pool *mem,
        if (lv_is_cow(lv))
                return _lvname_disp(rh, mem, field, origin_from_cow(lv), private);
 
+       if (lv_is_thin_volume(lv) && first_seg(lv)->origin)
+               return _lvname_disp(rh, mem, field, first_seg(lv)->origin, private);
+
        dm_report_field_set_value(field, "", NULL);
        return 1;
 }
@@ -411,7 +397,7 @@ static int _size32_disp(struct dm_report *rh __attribute__((unused)), struct dm_
                return 0;
        }
 
-       *sortval = (const uint64_t) size;
+       *sortval = (uint64_t) size;
 
        dm_report_field_set_value(field, repstr, sortval);
 
@@ -446,6 +432,20 @@ static int _size64_disp(struct dm_report *rh __attribute__((unused)),
        return 1;
 }
 
+static int _uint32_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
+                       struct dm_report_field *field,
+                       const void *data, void *private __attribute__((unused)))
+{
+       return dm_report_field_uint32(rh, field, data);
+}
+
+static int _int32_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
+                      struct dm_report_field *field,
+                      const void *data, void *private __attribute__((unused)))
+{
+       return dm_report_field_int32(rh, field, data);
+}
+
 static int _lvreadahead_disp(struct dm_report *rh, struct dm_pool *mem,
                             struct dm_report_field *field,
                             const void *data, void *private __attribute__((unused)))
@@ -533,6 +533,56 @@ static int _chunksize_disp(struct dm_report *rh, struct dm_pool *mem,
        return _size64_disp(rh, mem, field, &size, private);
 }
 
+static int _thinzero_disp(struct dm_report *rh, struct dm_pool *mem,
+                          struct dm_report_field *field,
+                          const void *data, void *private)
+{
+       const struct lv_segment *seg = (const struct lv_segment *) data;
+
+       /* Suppress thin count if not thin pool */
+       if (!seg_is_thin_pool(seg)) {
+               dm_report_field_set_value(field, "", NULL);
+               return 1;
+       }
+
+       return _uint32_disp(rh, mem, field, &seg->zero_new_blocks, private);
+}
+
+static int _transactionid_disp(struct dm_report *rh, struct dm_pool *mem,
+                               struct dm_report_field *field,
+                               const void *data, void *private)
+{
+       const struct lv_segment *seg = (const struct lv_segment *) data;
+
+       /* Suppress thin count if not thin pool */
+       if (!seg_is_thin_pool(seg)) {
+               dm_report_field_set_value(field, "", NULL);
+               return 1;
+       }
+
+       return  dm_report_field_uint64(rh, field, &seg->transaction_id);
+}
+
+static int _discards_disp(struct dm_report *rh, struct dm_pool *mem,
+                         struct dm_report_field *field,
+                         const void *data, void *private)
+{
+       const struct lv_segment *seg = (const struct lv_segment *) data;
+       const char *discards_str;
+
+       if (seg_is_thin_volume(seg))
+               seg = first_seg(seg->pool_lv);
+
+       if (seg_is_thin_pool(seg)) {
+               discards_str = get_pool_discards_name(seg->discards);
+               return dm_report_field_string(rh, field, &discards_str);
+       }
+
+       dm_report_field_set_value(field, "", NULL);
+
+       return 1;
+}
+
 static int _originsize_disp(struct dm_report *rh, struct dm_pool *mem,
                            struct dm_report_field *field,
                            const void *data, void *private)
@@ -615,27 +665,13 @@ static int _uuid_disp(struct dm_report *rh __attribute__((unused)), struct dm_po
 {
        char *repstr = NULL;
 
-       if (!(repstr = id_format_and_copy(mem, (struct id *)data)))
+       if (!(repstr = id_format_and_copy(mem, data)))
                return_0;
 
        dm_report_field_set_value(field, repstr, NULL);
        return 1;
 }
 
-static int _uint32_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
-                       struct dm_report_field *field,
-                       const void *data, void *private __attribute__((unused)))
-{
-       return dm_report_field_uint32(rh, field, data);
-}
-
-static int _int32_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
-                      struct dm_report_field *field,
-                      const void *data, void *private __attribute__((unused)))
-{
-       return dm_report_field_int32(rh, field, data);
-}
-
 static int _pvmdas_disp(struct dm_report *rh, struct dm_pool *mem,
                        struct dm_report_field *field,
                        const void *data, void *private)
@@ -818,7 +854,7 @@ static int _snpercent_disp(struct dm_report *rh __attribute__((unused)), struct
        }
 
        if (!lv_snapshot_percent(lv, &snap_percent) ||
-                                (snap_percent == PERCENT_INVALID)) {
+           (snap_percent == PERCENT_INVALID) || (snap_percent == PERCENT_MERGE_FAILED)) {
                if (!lv_is_merging_origin(lv)) {
                        *sortval = UINT64_C(100);
                        dm_report_field_set_value(field, "100.00", sortval);
@@ -853,7 +889,7 @@ static int _copypercent_disp(struct dm_report *rh __attribute__((unused)),
                             struct dm_report_field *field,
                             const void *data, void *private __attribute__((unused)))
 {
-       struct logical_volume *lv = (struct logical_volume *) data;
+       const struct logical_volume *lv = (const struct logical_volume *) data;
        percent_t percent;
        uint64_t *sortval;
        char *repstr;
@@ -889,6 +925,155 @@ static int _copypercent_disp(struct dm_report *rh __attribute__((unused)),
        return 1;
 }
 
+static int _dtpercent_disp(int metadata, struct dm_report *rh,
+                          struct dm_pool *mem,
+                          struct dm_report_field *field,
+                          const void *data, void *private)
+{
+       const struct logical_volume *lv = (const struct logical_volume *) data;
+       struct lvinfo info;
+       percent_t percent;
+       uint64_t *sortval;
+       char *repstr;
+
+       /* Suppress data percent if not thin pool/volume or not using driver */
+       if (!lv_info(lv->vg->cmd, lv, 1, &info, 0, 0) || !info.exists) {
+               dm_report_field_set_value(field, "", NULL);
+               return 1;
+       }
+
+       if (!(sortval = dm_pool_zalloc(mem, sizeof(uint64_t)))) {
+               log_error("Failed to allocate sortval.");
+               return 0;
+       }
+
+       if (lv_is_thin_pool(lv)) {
+               if (!lv_thin_pool_percent(lv, metadata, &percent))
+                       return_0;
+       } else { /* thin_volume */
+               if (!lv_thin_percent(lv, 0, &percent))
+                       return_0;
+       }
+
+       if (!(repstr = dm_pool_alloc(mem, 8))) {
+               log_error("Failed to allocate report buffer.");
+               return 0;
+       }
+
+       if (dm_snprintf(repstr, 8, "%.2f", percent_to_float(percent)) < 0) {
+               log_error("Data percentage too large.");
+               return 0;
+       }
+
+       *sortval = (uint64_t)(percent * 1000.f);
+       dm_report_field_set_value(field, repstr, sortval);
+
+       return 1;
+}
+
+static int _datapercent_disp(struct dm_report *rh, struct dm_pool *mem,
+                            struct dm_report_field *field,
+                            const void *data, void *private)
+{
+       const struct logical_volume *lv = (const struct logical_volume *) data;
+
+       if (lv_is_cow(lv))
+               return _snpercent_disp(rh, mem, field, data, private);
+
+       if (lv_is_thin_pool(lv) || lv_is_thin_volume(lv))
+               return _dtpercent_disp(0, rh, mem, field, data, private);
+
+       dm_report_field_set_value(field, "", NULL);
+
+       return 1;
+}
+
+static int _metadatapercent_disp(struct dm_report *rh, struct dm_pool *mem,
+                                struct dm_report_field *field,
+                                const void *data, void *private)
+{
+       const struct logical_volume *lv = (const struct logical_volume *) data;
+
+       if (lv_is_thin_pool(lv))
+               return _dtpercent_disp(1, rh, mem, field, data, private);
+
+       dm_report_field_set_value(field, "", NULL);
+
+       return 1;
+}
+
+static int _lvmetadatasize_disp(struct dm_report *rh, struct dm_pool *mem,
+                               struct dm_report_field *field,
+                               const void *data, void *private)
+{
+       const struct logical_volume *lv = (const struct logical_volume *) data;
+       uint64_t size;
+
+       if (!lv_is_thin_pool(lv)) {
+               dm_report_field_set_value(field, "", NULL);
+               return 1;
+       }
+
+       size = lv_metadata_size(lv);
+
+       return _size64_disp(rh, mem, field, &size, private);
+}
+
+static int _thincount_disp(struct dm_report *rh, struct dm_pool *mem,
+                         struct dm_report_field *field,
+                         const void *data, void *private)
+{
+       const struct lv_segment *seg = (const struct lv_segment *) data;
+       uint32_t count;
+
+       /* Suppress thin count if not thin pool */
+       if (!seg_is_thin_pool(seg)) {
+               dm_report_field_set_value(field, "", NULL);
+               return 1;
+       }
+
+       count = dm_list_size(&seg->lv->segs_using_this_lv);
+
+       return _uint32_disp(rh, mem, field, &count, private);
+}
+
+static int _lvtime_disp(struct dm_report *rh, struct dm_pool *mem,
+                       struct dm_report_field *field,
+                       const void *data, void *private)
+{
+       const struct logical_volume *lv = (const struct logical_volume *) data;
+       char *repstr;
+       uint64_t *sortval;
+
+       if (!(sortval = dm_pool_zalloc(mem, sizeof(uint64_t)))) {
+               log_error("Failed to allocate sortval.");
+               return 0;
+       }
+
+       *sortval = lv->timestamp;
+       if (!(repstr = lv_time_dup(mem, lv)))
+               return_0;
+
+       dm_report_field_set_value(field, repstr, sortval);
+
+       return 1;
+}
+
+static int _lvhost_disp(struct dm_report *rh, struct dm_pool *mem,
+                       struct dm_report_field *field,
+                       const void *data, void *private)
+{
+       const struct logical_volume *lv = (const struct logical_volume *) data;
+       char *repstr;
+
+       if (!(repstr = lv_host_dup(mem, lv)))
+               return_0;
+
+       dm_report_field_set_value(field, repstr, repstr);
+
+       return 1;
+}
+
 /* Report object types */
 
 /* necessary for displaying something for PVs not belonging to VG */
@@ -899,7 +1084,7 @@ static struct format_instance _dummy_fid = {
 
 static struct volume_group _dummy_vg = {
        .fid = &_dummy_fid,
-       .name = (char *) "",
+       .name = "",
        .system_id = (char *) "",
        .pvs = { &(_dummy_vg.pvs), &(_dummy_vg.pvs) },
        .lvs = { &(_dummy_vg.lvs), &(_dummy_vg.lvs) },
index 1a98d7e0d993c1f8677840b7d3f9d6c437c07849..662614ce8b3ff2424e3d6d941c0322a9d93a8aaa 100644 (file)
@@ -28,15 +28,16 @@ static const char *_snap_name(const struct lv_segment *seg)
        return seg->segtype->name;
 }
 
-static const char *_snap_target_name(const struct lv_segment *seg)
+static const char *_snap_target_name(const struct lv_segment *seg,
+                                    const struct lv_activate_opts *laopts)
 {
-       if (seg->status & MERGING)
+       if (!laopts->no_merging && (seg->status & MERGING))
                return "snapshot-merge";
 
        return _snap_name(seg);
 }
 
-static int _snap_text_import(struct lv_segment *seg, const struct config_node *sn,
+static int _snap_text_import(struct lv_segment *seg, const struct dm_config_node *sn,
                        struct dm_hash_table *pv_hash __attribute__((unused)))
 {
        uint32_t chunk_size;
@@ -44,28 +45,28 @@ static int _snap_text_import(struct lv_segment *seg, const struct config_node *s
        struct logical_volume *org, *cow;
        int old_suppress, merge = 0;
 
-       if (!get_config_uint32(sn, "chunk_size", &chunk_size)) {
+       if (!dm_config_get_uint32(sn, "chunk_size", &chunk_size)) {
                log_error("Couldn't read chunk size for snapshot.");
                return 0;
        }
 
        old_suppress = log_suppress(1);
 
-       if ((cow_name = find_config_str(sn, "merging_store", NULL))) {
-               if (find_config_str(sn, "cow_store", NULL)) {
+       if ((cow_name = dm_config_find_str(sn, "merging_store", NULL))) {
+               if (dm_config_find_str(sn, "cow_store", NULL)) {
                        log_suppress(old_suppress);
                        log_error("Both snapshot cow and merging storage were specified.");
                        return 0;
                }
                merge = 1;
        }
-       else if (!(cow_name = find_config_str(sn, "cow_store", NULL))) {
+       else if (!(cow_name = dm_config_find_str(sn, "cow_store", NULL))) {
                log_suppress(old_suppress);
                log_error("Snapshot cow storage not specified.");
                return 0;
        }
 
-       if (!(org_name = find_config_str(sn, "origin", NULL))) {
+       if (!(org_name = dm_config_find_str(sn, "origin", NULL))) {
                log_suppress(old_suppress);
                log_error("Snapshot origin not specified.");
                return 0;
@@ -135,9 +136,11 @@ static int _snap_target_percent(void **target_state __attribute__((unused)),
                        *percent = PERCENT_100;
                else
                        *percent = make_percent(*total_numerator, *total_denominator);
-       } else if (!strcmp(params, "Invalid") ||
-                  !strcmp(params, "Merge failed"))
+       }
+       else if (!strcmp(params, "Invalid"))
                *percent = PERCENT_INVALID;
+       else if (!strcmp(params, "Merge failed"))
+               *percent = PERCENT_MERGE_FAILED;
        else
                return 0;
 
@@ -232,11 +235,11 @@ static struct segtype_handler _snapshot_ops = {
 #ifdef DEVMAPPER_SUPPORT
        .target_percent = _snap_target_percent,
        .target_present = _snap_target_present,
-#ifdef DMEVENTD
+#  ifdef DMEVENTD
        .target_monitored = _target_registered,
        .target_monitor_events = _target_register_events,
        .target_unmonitor_events = _target_unregister_events,
-#endif
+#  endif       /* DMEVENTD */
 #endif
        .modules_needed = _snap_modules_needed,
        .destroy = _snap_destroy,
@@ -249,7 +252,7 @@ struct segment_type *init_segtype(struct cmd_context *cmd);
 struct segment_type *init_segtype(struct cmd_context *cmd)
 #endif
 {
-       struct segment_type *segtype = dm_malloc(sizeof(*segtype));
+       struct segment_type *segtype = dm_zalloc(sizeof(*segtype));
 
        if (!segtype)
                return_NULL;
@@ -260,9 +263,11 @@ struct segment_type *init_segtype(struct cmd_context *cmd)
        segtype->private = NULL;
        segtype->flags = SEG_SNAPSHOT;
 
-#ifdef DMEVENTD
+#ifdef DEVMAPPER_SUPPORT
+#  ifdef DMEVENTD
        if (_get_snapshot_dso_path(cmd))
                segtype->flags |= SEG_MONITORED;
+#  endif       /* DMEVENTD */
 #endif
        log_very_verbose("Initialised segtype: %s", segtype->name);
 
index 51bf24a1e320ee1787a181637d4cd61a4c08b399..3b0846780dba9ad0120cc91e32a85888bec74b27 100644 (file)
@@ -57,38 +57,38 @@ static void _striped_display(const struct lv_segment *seg)
        log_print(" ");
 }
 
-static int _striped_text_import_area_count(const struct config_node *sn, uint32_t *area_count)
+static int _striped_text_import_area_count(const struct dm_config_node *sn, uint32_t *area_count)
 {
-       if (!get_config_uint32(sn, "stripe_count", area_count)) {
+       if (!dm_config_get_uint32(sn, "stripe_count", area_count)) {
                log_error("Couldn't read 'stripe_count' for "
-                         "segment '%s'.", config_parent_name(sn));
+                         "segment '%s'.", dm_config_parent_name(sn));
                return 0;
        }
 
        return 1;
 }
 
-static int _striped_text_import(struct lv_segment *seg, const struct config_node *sn,
+static int _striped_text_import(struct lv_segment *seg, const struct dm_config_node *sn,
                        struct dm_hash_table *pv_hash)
 {
-       const struct config_node *cn;
+       const struct dm_config_value *cv;
 
        if ((seg->area_count != 1) &&
-           !get_config_uint32(sn, "stripe_size", &seg->stripe_size)) {
+           !dm_config_get_uint32(sn, "stripe_size", &seg->stripe_size)) {
                log_error("Couldn't read stripe_size for segment %s "
-                         "of logical volume %s.", config_parent_name(sn), seg->lv->name);
+                         "of logical volume %s.", dm_config_parent_name(sn), seg->lv->name);
                return 0;
        }
 
-       if (!(cn = find_config_node(sn, "stripes"))) {
+       if (!dm_config_get_list(sn, "stripes", &cv)) {
                log_error("Couldn't find stripes array for segment %s "
-                         "of logical volume %s.", config_parent_name(sn), seg->lv->name);
+                         "of logical volume %s.", dm_config_parent_name(sn), seg->lv->name);
                return 0;
        }
 
        seg->area_len /= seg->area_count;
 
-       return text_import_areas(seg, sn, cn, pv_hash, 0);
+       return text_import_areas(seg, sn, cv, pv_hash, 0);
 }
 
 static int _striped_text_export(const struct lv_segment *seg, struct formatter *f)
@@ -164,6 +164,7 @@ static int _striped_add_target_line(struct dev_manager *dm,
                                struct cmd_context *cmd __attribute__((unused)),
                                void **target_state __attribute__((unused)),
                                struct lv_segment *seg,
+                               const struct lv_activate_opts *laopts __attribute__((unused)),
                                struct dm_tree_node *node, uint64_t len,
                                uint32_t *pvmove_mirror_count __attribute__((unused)))
 {
@@ -173,7 +174,9 @@ static int _striped_add_target_line(struct dev_manager *dm,
                return 0;
        }
        if (seg->area_count == 1) {
-               if (!dm_tree_node_add_linear_target(node, len))
+               if (!add_linear_area_to_dtree(node, len, seg->lv->vg->extent_size,
+                                             cmd->use_linear_target,
+                                             seg->lv->vg->name, seg->lv->name))
                        return_0;
        } else if (!dm_tree_node_add_striped_target(node, len,
                                                  seg->stripe_size))
@@ -220,7 +223,7 @@ static struct segtype_handler _striped_ops = {
 
 struct segment_type *init_striped_segtype(struct cmd_context *cmd)
 {
-       struct segment_type *segtype = dm_malloc(sizeof(*segtype));
+       struct segment_type *segtype = dm_zalloc(sizeof(*segtype));
 
        if (!segtype)
                return_NULL;
diff --git a/lib/thin/.exported_symbols b/lib/thin/.exported_symbols
new file mode 100644 (file)
index 0000000..1c92c6a
--- /dev/null
@@ -0,0 +1 @@
+init_segtype
diff --git a/lib/thin/Makefile.in b/lib/thin/Makefile.in
new file mode 100644 (file)
index 0000000..caa1892
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = @top_builddir@
+
+SOURCES = thin.c
+
+LIB_SHARED = liblvm2thin.$(LIB_SUFFIX)
+LIB_VERSION = $(LIB_VERSION_LVM)
+
+include $(top_builddir)/make.tmpl
+
+install: install_lib_shared_plugin
diff --git a/lib/thin/thin.c b/lib/thin/thin.c
new file mode 100644 (file)
index 0000000..2b6c71f
--- /dev/null
@@ -0,0 +1,675 @@
+/*
+ * Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "lib.h"
+#include "toolcontext.h"
+#include "metadata.h"
+#include "segtype.h"
+#include "text_export.h"
+#include "config.h"
+#include "activate.h"
+#include "str_list.h"
+#include "defaults.h"
+
+#ifdef DMEVENTD
+#  include "libdevmapper-event.h"
+#endif
+
+/* Dm kernel module name for thin provisiong */
+#define THIN_MODULE "thin-pool"
+
+/*
+ * Macro used as return argument - returns 0.
+ * return is left to be written in the function for better readability.
+ */
+#define SEG_LOG_ERROR(t, p...) \
+       log_error(t " segment %s of logical volume %s.", ## p, \
+                 dm_config_parent_name(sn), seg->lv->name), 0;
+
+static int _thin_target_present(struct cmd_context *cmd,
+                               const struct lv_segment *seg,
+                               unsigned *attributes);
+
+static const char *_thin_pool_name(const struct lv_segment *seg)
+{
+       return seg->segtype->name;
+}
+
+static int _thin_pool_add_message(struct lv_segment *seg,
+                                 const char *key,
+                                 const struct dm_config_node *sn)
+{
+       const char *lv_name = NULL;
+       struct logical_volume *lv = NULL;
+       uint32_t delete_id = 0;
+       dm_thin_message_t type;
+
+       /* Message must have only one from: create, delete */
+       if (dm_config_get_str(sn, "create", &lv_name)) {
+               if (!(lv = find_lv(seg->lv->vg, lv_name)))
+                       return SEG_LOG_ERROR("Unknown LV %s for create message in",
+                                            lv_name);
+               /* FIXME: switch to _SNAP later, if the created LV has an origin */
+               type = DM_THIN_MESSAGE_CREATE_THIN;
+       }
+
+       if (!dm_config_get_uint32(sn, "delete", &delete_id)) {
+               if (!lv)
+                       return SEG_LOG_ERROR("Unknown message in");
+       } else {
+               if (lv)
+                       return SEG_LOG_ERROR("Unsupported message format in");
+               type = DM_THIN_MESSAGE_DELETE;
+       }
+
+       if (!attach_pool_message(seg, type, lv, delete_id, 1))
+               return_0;
+
+       return 1;
+}
+
+static int _thin_pool_text_import(struct lv_segment *seg,
+                                 const struct dm_config_node *sn,
+                                 struct dm_hash_table *pv_hash __attribute__((unused)))
+{
+       const char *lv_name;
+       struct logical_volume *pool_data_lv, *pool_metadata_lv;
+       const char *discards_str = NULL;
+
+       if (!dm_config_get_str(sn, "metadata", &lv_name))
+               return SEG_LOG_ERROR("Metadata must be a string in");
+
+       if (!(pool_metadata_lv = find_lv(seg->lv->vg, lv_name)))
+               return SEG_LOG_ERROR("Unknown metadata %s in", lv_name);
+
+       if (!dm_config_get_str(sn, "pool", &lv_name))
+               return SEG_LOG_ERROR("Pool must be a string in");
+
+       if (!(pool_data_lv = find_lv(seg->lv->vg, lv_name)))
+               return SEG_LOG_ERROR("Unknown pool %s in", lv_name);
+
+       seg->lv->status |= THIN_POOL;
+       if (!attach_pool_metadata_lv(seg, pool_metadata_lv))
+               return_0;
+
+       if (!attach_pool_data_lv(seg, pool_data_lv))
+               return_0;
+
+       if (!dm_config_get_uint64(sn, "transaction_id", &seg->transaction_id))
+               return SEG_LOG_ERROR("Could not read transaction_id for");
+
+       if (!dm_config_get_uint32(sn, "chunk_size", &seg->chunk_size))
+               return SEG_LOG_ERROR("Could not read chunk_size");
+
+       if (dm_config_has_node(sn, "discards") &&
+           !dm_config_get_str(sn, "discards", &discards_str))
+               return SEG_LOG_ERROR("Could not read discards for");
+
+       if (!discards_str)
+               seg->discards = THIN_DISCARDS_IGNORE;
+       else if (!get_pool_discards(discards_str, &seg->discards))
+               return SEG_LOG_ERROR("Discards option unsupported for");
+
+       if (dm_config_has_node(sn, "low_water_mark") &&
+           !dm_config_get_uint64(sn, "low_water_mark", &seg->low_water_mark))
+               return SEG_LOG_ERROR("Could not read low_water_mark");
+
+       if ((seg->chunk_size < DM_THIN_MIN_DATA_BLOCK_SIZE) ||
+           (seg->chunk_size > DM_THIN_MAX_DATA_BLOCK_SIZE))
+               return SEG_LOG_ERROR("Unsupported value %u for chunk_size",
+                                    seg->device_id);
+
+       if (dm_config_has_node(sn, "zero_new_blocks") &&
+           !dm_config_get_uint32(sn, "zero_new_blocks", &seg->zero_new_blocks))
+               return SEG_LOG_ERROR("Could not read zero_new_blocks for");
+
+       /* Read messages */
+       for (; sn; sn = sn->sib)
+               if (!(sn->v) && !_thin_pool_add_message(seg, sn->key, sn->child))
+                       return_0;
+
+       return 1;
+}
+
+static int _thin_pool_text_import_area_count(const struct dm_config_node *sn,
+                                            uint32_t *area_count)
+{
+       *area_count = 1;
+
+       return 1;
+}
+
+static int _thin_pool_text_export(const struct lv_segment *seg, struct formatter *f)
+{
+       unsigned cnt = 0;
+       const struct lv_thin_message *tmsg;
+
+       outf(f, "metadata = \"%s\"", seg->metadata_lv->name);
+       outf(f, "pool = \"%s\"", seg_lv(seg, 0)->name);
+       outf(f, "transaction_id = %" PRIu64, seg->transaction_id);
+       outsize(f, (uint64_t) seg->chunk_size,
+               "chunk_size = %u", seg->chunk_size);
+
+       switch (seg->discards) {
+       case THIN_DISCARDS_PASSDOWN:
+       case THIN_DISCARDS_NO_PASSDOWN:
+       case THIN_DISCARDS_IGNORE:
+               outf(f, "discards = \"%s\"", get_pool_discards_name(seg->discards));
+               break;
+       default:
+               log_error(INTERNAL_ERROR "Invalid discards value %d.", seg->discards);
+               return 0;
+       }
+
+       if (seg->low_water_mark)
+               outf(f, "low_water_mark = %" PRIu64, seg->low_water_mark);
+
+       if (seg->zero_new_blocks)
+               outf(f, "zero_new_blocks = 1");
+
+       dm_list_iterate_items(tmsg, &seg->thin_messages) {
+               /* Extra validation */
+               switch (tmsg->type) {
+               case DM_THIN_MESSAGE_CREATE_SNAP:
+               case DM_THIN_MESSAGE_CREATE_THIN:
+                       if (!lv_is_thin_volume(tmsg->u.lv)) {
+                               log_error(INTERNAL_ERROR
+                                         "LV %s is not a thin volume.",
+                                         tmsg->u.lv->name);
+                               return 0;
+                       }
+                       break;
+               default:
+                       break;
+               }
+
+               if (!cnt)
+                       outnl(f);
+
+               outf(f, "message%d {", ++cnt);
+               out_inc_indent(f);
+
+               switch (tmsg->type) {
+               case DM_THIN_MESSAGE_CREATE_SNAP:
+               case DM_THIN_MESSAGE_CREATE_THIN:
+                       outf(f, "create = \"%s\"", tmsg->u.lv->name);
+                       break;
+               case DM_THIN_MESSAGE_DELETE:
+                       outf(f, "delete = %d", tmsg->u.delete_id);
+                       break;
+               default:
+                       log_error(INTERNAL_ERROR "Passed unsupported message.");
+                       return 0;
+               }
+
+               out_dec_indent(f);
+               outf(f, "}");
+       }
+
+       return 1;
+}
+
+#ifdef DEVMAPPER_SUPPORT
+static int _thin_pool_add_target_line(struct dev_manager *dm,
+                                     struct dm_pool *mem,
+                                     struct cmd_context *cmd,
+                                     void **target_state __attribute__((unused)),
+                                     struct lv_segment *seg,
+                                     const struct lv_activate_opts *laopts,
+                                     struct dm_tree_node *node, uint64_t len,
+                                     uint32_t *pvmove_mirror_count __attribute__((unused)))
+{
+       static int _no_discards = 0;
+       char *metadata_dlid, *pool_dlid;
+       const struct lv_thin_message *lmsg;
+       const struct logical_volume *origin;
+       struct lvinfo info;
+       uint64_t transaction_id = 0;
+       unsigned attr;
+
+       if (!_thin_target_present(cmd, seg, &attr))
+               return_0;
+
+       if (!(attr & THIN_FEATURE_BLOCK_SIZE) &&
+           (seg->chunk_size & (seg->chunk_size - 1))) {
+               log_error("Thin pool target does not support %uKiB chunk size "
+                         "(needs kernel >= 3.6).", seg->chunk_size / 2);
+               return 0;
+       }
+
+       if (!laopts->real_pool) {
+               if (!(pool_dlid = build_dm_uuid(mem, seg->lv->lvid.s, "tpool"))) {
+                       log_error("Failed to build uuid for thin pool LV %s.", seg->pool_lv->name);
+                       return 0;
+               }
+
+               if (!add_linear_area_to_dtree(node, len, seg->lv->vg->extent_size,
+                                             cmd->use_linear_target,
+                                             seg->lv->vg->name, seg->lv->name) ||
+                   !dm_tree_node_add_target_area(node, NULL, pool_dlid, 0))
+                       return_0;
+
+               return 1;
+       }
+
+       if (!(metadata_dlid = build_dm_uuid(mem, seg->metadata_lv->lvid.s, NULL))) {
+               log_error("Failed to build uuid for metadata LV %s.",
+                         seg->metadata_lv->name);
+               return 0;
+       }
+
+       if (!(pool_dlid = build_dm_uuid(mem, seg_lv(seg, 0)->lvid.s, NULL))) {
+               log_error("Failed to build uuid for pool LV %s.",
+                         seg_lv(seg, 0)->name);
+               return 0;
+       }
+
+       if (!dm_tree_node_add_thin_pool_target(node, len, seg->transaction_id,
+                                              metadata_dlid, pool_dlid,
+                                              seg->chunk_size, seg->low_water_mark,
+                                              seg->zero_new_blocks ? 0 : 1))
+               return_0;
+
+       if (attr & THIN_FEATURE_DISCARDS) {
+               /* FIXME: Check whether underlying dev supports discards */
+               if (!dm_tree_node_set_thin_pool_discard(node,
+                                                       seg->discards == THIN_DISCARDS_IGNORE,
+                                                       seg->discards == THIN_DISCARDS_NO_PASSDOWN))
+                       return_0;
+       } else if (seg->discards != THIN_DISCARDS_IGNORE)
+               log_warn_suppress(_no_discards++, "WARNING: Thin pool target does "
+                                 "not support discards (needs kernel >= 3.4).");
+
+       /*
+        * Add messages only for activation tree.
+        * Otherwise avoid checking for existence of suspended origin.
+        * Also transation_id is checked only when snapshot origin is active.
+        * (This might change later)
+        */
+       if (!laopts->is_activate)
+               return 1;
+
+       dm_list_iterate_items(lmsg, &seg->thin_messages) {
+               switch (lmsg->type) {
+               case DM_THIN_MESSAGE_CREATE_THIN:
+                       origin = first_seg(lmsg->u.lv)->origin;
+                       /* Check if the origin is suspended */
+                       if (origin && lv_info(cmd, origin, 0, &info, 0, 0) &&
+                           info.exists && !info.suspended) {
+                               /* Origin is not suspended, but the transaction may have been
+                                * already transfered, so test for transaction_id and
+                                * allow to pass in the message for dmtree processing
+                                * so it will skip all messages later.
+                                */
+                               if (!lv_thin_pool_transaction_id(seg->lv, &transaction_id))
+                                       return_0; /* Thin pool should exist and work */
+                               if (transaction_id != seg->transaction_id) {
+                                       log_error("Can't create snapshot %s as origin %s is not suspended.",
+                                                 lmsg->u.lv->name, origin->name);
+                                       return 0;
+                               }
+                       }
+                       log_debug("Thin pool create_%s %s.", (!origin) ? "thin" : "snap", lmsg->u.lv->name);
+                       if (!dm_tree_node_add_thin_pool_message(node,
+                                                               (!origin) ? lmsg->type : DM_THIN_MESSAGE_CREATE_SNAP,
+                                                               first_seg(lmsg->u.lv)->device_id,
+                                                               (!origin) ? 0 : first_seg(origin)->device_id))
+                               return_0;
+                       break;
+               case DM_THIN_MESSAGE_DELETE:
+                       log_debug("Thin pool delete %u.", lmsg->u.delete_id);
+                       if (!dm_tree_node_add_thin_pool_message(node,
+                                                               lmsg->type,
+                                                               lmsg->u.delete_id, 0))
+                               return_0;
+                       break;
+               default:
+                       log_error(INTERNAL_ERROR "Unsupported message.");
+                       return 0;
+               }
+       }
+
+       if (!dm_list_empty(&seg->thin_messages)) {
+               /* Messages were passed, modify transaction_id as the last one */
+               log_debug("Thin pool set transaction id %" PRIu64 ".", seg->transaction_id);
+               if (!dm_tree_node_add_thin_pool_message(node,
+                                                       DM_THIN_MESSAGE_SET_TRANSACTION_ID,
+                                                       seg->transaction_id - 1,
+                                                       seg->transaction_id))
+                       return_0;
+       }
+
+       return 1;
+}
+
+static int _thin_pool_target_percent(void **target_state __attribute__((unused)),
+                                    percent_t *percent,
+                                    struct dm_pool *mem,
+                                    struct cmd_context *cmd __attribute__((unused)),
+                                    struct lv_segment *seg,
+                                    char *params,
+                                    uint64_t *total_numerator,
+                                    uint64_t *total_denominator)
+{
+       struct dm_status_thin_pool *s;
+
+       if (!dm_get_status_thin_pool(mem, params, &s))
+               return_0;
+
+       /* With 'seg' report metadata percent, otherwice data percent */
+       if (seg) {
+               *percent = make_percent(s->used_metadata_blocks,
+                                       s->total_metadata_blocks);
+               *total_numerator += s->used_metadata_blocks;
+               *total_denominator += s->total_metadata_blocks;
+       } else {
+               *percent = make_percent(s->used_data_blocks,
+                                       s->total_data_blocks);
+               *total_numerator += s->used_data_blocks;
+               *total_denominator += s->total_data_blocks;
+       }
+
+       return 1;
+}
+
+#  ifdef DMEVENTD
+static const char *_get_thin_dso_path(struct cmd_context *cmd)
+{
+       return get_monitor_dso_path(cmd, find_config_tree_str(cmd, "dmeventd/thin_library",
+                                                             DEFAULT_DMEVENTD_THIN_LIB));
+}
+
+/* FIXME Cache this */
+static int _target_registered(struct lv_segment *seg, int *pending)
+{
+       return target_registered_with_dmeventd(seg->lv->vg->cmd,
+                                              _get_thin_dso_path(seg->lv->vg->cmd),
+                                              seg->lv, pending);
+}
+
+/* FIXME This gets run while suspended and performs banned operations. */
+static int _target_set_events(struct lv_segment *seg, int evmask, int set)
+{
+       /* FIXME Make timeout (10) configurable */
+       return target_register_events(seg->lv->vg->cmd,
+                                     _get_thin_dso_path(seg->lv->vg->cmd),
+                                     seg->lv, evmask, set, 10);
+}
+
+static int _target_register_events(struct lv_segment *seg,
+                                  int events)
+{
+       return _target_set_events(seg, events, 1);
+}
+
+static int _target_unregister_events(struct lv_segment *seg,
+                                    int events)
+{
+       return _target_set_events(seg, events, 0);
+}
+#  endif /* DMEVENTD */
+#endif /* DEVMAPPER_SUPPORT */
+
+static const char *_thin_name(const struct lv_segment *seg)
+{
+       return seg->segtype->name;
+}
+
+static int _thin_text_import(struct lv_segment *seg,
+                            const struct dm_config_node *sn,
+                            struct dm_hash_table *pv_hash __attribute__((unused)))
+{
+       const char *lv_name;
+       struct logical_volume *pool_lv, *origin = NULL;
+
+       if (!dm_config_get_str(sn, "thin_pool", &lv_name))
+               return SEG_LOG_ERROR("Thin pool must be a string in");
+
+       if (!(pool_lv = find_lv(seg->lv->vg, lv_name)))
+               return SEG_LOG_ERROR("Unknown thin pool %s in", lv_name);
+
+       if (!dm_config_get_uint64(sn, "transaction_id", &seg->transaction_id))
+               return SEG_LOG_ERROR("Could not read transaction_id for");
+
+       if (dm_config_has_node(sn, "origin")) {
+               if (!dm_config_get_str(sn, "origin", &lv_name))
+                       return SEG_LOG_ERROR("Origin must be a string in");
+
+               if (!(origin = find_lv(seg->lv->vg, lv_name)))
+                       return SEG_LOG_ERROR("Unknown origin %s in", lv_name);
+       }
+
+       if (!dm_config_get_uint32(sn, "device_id", &seg->device_id))
+               return SEG_LOG_ERROR("Could not read device_id for");
+
+       if (seg->device_id > DM_THIN_MAX_DEVICE_ID)
+               return SEG_LOG_ERROR("Unsupported value %u for device_id",
+                                    seg->device_id);
+
+       if (!attach_pool_lv(seg, pool_lv, origin))
+               return_0;
+
+       return 1;
+}
+
+static int _thin_text_export(const struct lv_segment *seg, struct formatter *f)
+{
+       outf(f, "thin_pool = \"%s\"", seg->pool_lv->name);
+       outf(f, "transaction_id = %" PRIu64, seg->transaction_id);
+       outf(f, "device_id = %d", seg->device_id);
+
+       if (seg->origin)
+               outf(f, "origin = \"%s\"", seg->origin->name);
+
+       return 1;
+}
+
+#ifdef DEVMAPPER_SUPPORT
+static int _thin_add_target_line(struct dev_manager *dm,
+                                struct dm_pool *mem,
+                                struct cmd_context *cmd __attribute__((unused)),
+                                void **target_state __attribute__((unused)),
+                                struct lv_segment *seg,
+                                const struct lv_activate_opts *laopts __attribute__((unused)),
+                                struct dm_tree_node *node, uint64_t len,
+                                uint32_t *pvmove_mirror_count __attribute__((unused)))
+{
+       char *pool_dlid;
+       uint32_t device_id = seg->device_id;
+
+       if (!(pool_dlid = build_dm_uuid(mem, seg->pool_lv->lvid.s, "tpool"))) {
+               log_error("Failed to build uuid for pool LV %s.",
+                         seg->pool_lv->name);
+               return 0;
+       }
+
+       if (!dm_tree_node_add_thin_target(node, len, pool_dlid, device_id))
+               return_0;
+
+       return 1;
+}
+
+static int _thin_target_percent(void **target_state __attribute__((unused)),
+                               percent_t *percent,
+                               struct dm_pool *mem,
+                               struct cmd_context *cmd __attribute__((unused)),
+                               struct lv_segment *seg,
+                               char *params,
+                               uint64_t *total_numerator,
+                               uint64_t *total_denominator)
+{
+       struct dm_status_thin *s;
+
+       /* Status for thin device is in sectors */
+       if (!dm_get_status_thin(mem, params, &s))
+               return_0;
+
+       if (seg) {
+               *percent = make_percent(s->mapped_sectors, seg->lv->size);
+               *total_denominator += seg->lv->size;
+       } else {
+               /* No lv_segment info here */
+               *percent = PERCENT_INVALID;
+               /* FIXME: Using denominator to pass the mapped info upward? */
+               *total_denominator += s->highest_mapped_sector;
+       }
+
+       *total_numerator += s->mapped_sectors;
+
+       return 1;
+}
+
+static int _thin_target_present(struct cmd_context *cmd,
+                               const struct lv_segment *seg,
+                               unsigned *attributes)
+{
+       static int _checked = 0;
+       static int _present = 0;
+       static int _attrs = 0;
+       uint32_t maj, min, patchlevel;
+
+       if (!_checked) {
+               _present = target_present(cmd, THIN_MODULE, 1);
+
+               if (!target_version(THIN_MODULE, &maj, &min, &patchlevel)) {
+                       log_error("Cannot read " THIN_MODULE " target version.");
+                       return 0;
+               }
+
+               if (maj >=1 && min >= 1)
+                       _attrs |= THIN_FEATURE_DISCARDS;
+               else
+               /* FIXME Log this as WARNING later only if the user asked for the feature to be used but it's not present */
+                       log_debug("Target " THIN_MODULE " does not support discards.");
+
+               if (maj >=1 && min >= 1)
+                       _attrs |= THIN_FEATURE_EXTERNAL_ORIGIN;
+               else
+               /* FIXME Log this as WARNING later only if the user asked for the feature to be used but it's not present */
+                       log_debug("Target " THIN_MODULE " does not support external origins.");
+
+               if (maj >=1 && min >= 4)
+                       _attrs |= THIN_FEATURE_BLOCK_SIZE;
+               else
+               /* FIXME Log this as WARNING later only if the user asked for the feature to be used but it's not present */
+                       log_debug("Target " THIN_MODULE " does not support non power of 2 block sizes.");
+
+               _checked = 1;
+       }
+
+       if (attributes)
+               *attributes = _attrs;
+
+       return _present;
+}
+#endif
+
+static int _thin_modules_needed(struct dm_pool *mem,
+                               const struct lv_segment *seg __attribute__((unused)),
+                               struct dm_list *modules)
+{
+       if (!str_list_add(mem, modules, THIN_MODULE)) {
+               log_error("thin string list allocation failed");
+               return 0;
+       }
+
+       return 1;
+}
+
+static void _thin_destroy(struct segment_type *segtype)
+{
+       dm_free(segtype);
+}
+
+static struct segtype_handler _thin_pool_ops = {
+       .name = _thin_pool_name,
+       .text_import = _thin_pool_text_import,
+       .text_import_area_count = _thin_pool_text_import_area_count,
+       .text_export = _thin_pool_text_export,
+#ifdef DEVMAPPER_SUPPORT
+       .add_target_line = _thin_pool_add_target_line,
+       .target_percent = _thin_pool_target_percent,
+       .target_present = _thin_target_present,
+#  ifdef DMEVENTD
+       .target_monitored = _target_registered,
+       .target_monitor_events = _target_register_events,
+       .target_unmonitor_events = _target_unregister_events,
+#  endif /* DMEVENTD */
+#endif
+       .modules_needed = _thin_modules_needed,
+       .destroy = _thin_destroy,
+};
+
+static struct segtype_handler _thin_ops = {
+       .name = _thin_name,
+       .text_import = _thin_text_import,
+       .text_export = _thin_text_export,
+#ifdef DEVMAPPER_SUPPORT
+       .add_target_line = _thin_add_target_line,
+       .target_percent = _thin_target_percent,
+       .target_present = _thin_target_present,
+#endif
+       .modules_needed = _thin_modules_needed,
+       .destroy = _thin_destroy,
+};
+
+#ifdef THIN_INTERNAL
+int init_thin_segtypes(struct cmd_context *cmd, struct segtype_library *seglib)
+#else /* Shared */
+int init_multiple_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
+int init_multiple_segtypes(struct cmd_context *cmd, struct segtype_library *seglib)
+#endif
+{
+       static const struct {
+               struct segtype_handler *ops;
+               const char name[16];
+               uint32_t flags;
+       } reg_segtypes[] = {
+               { &_thin_pool_ops, "thin-pool", SEG_THIN_POOL },
+               /* FIXME Maybe use SEG_THIN_VOLUME instead of SEG_VIRTUAL */
+               { &_thin_ops, "thin", SEG_THIN_VOLUME | SEG_VIRTUAL }
+       };
+
+       struct segment_type *segtype;
+       unsigned i;
+
+       for (i = 0; i < sizeof(reg_segtypes)/sizeof(reg_segtypes[0]); ++i) {
+               segtype = dm_zalloc(sizeof(*segtype));
+
+               if (!segtype) {
+                       log_error("Failed to allocate memory for %s segtype",
+                                 reg_segtypes[i].name);
+                       return 0;
+               }
+
+               segtype->ops = reg_segtypes[i].ops;
+               segtype->name = reg_segtypes[i].name;
+               segtype->flags = reg_segtypes[i].flags;
+
+#ifdef DEVMAPPER_SUPPORT
+#  ifdef DMEVENTD
+               if ((reg_segtypes[i].flags & SEG_THIN_POOL) &&
+                   _get_thin_dso_path(cmd))
+                       segtype->flags |= SEG_MONITORED;
+#  endif /* DMEVENTD */
+#endif
+               if (!lvm_register_segtype(seglib, segtype))
+                       /* segtype is already destroyed */
+                       return_0;
+
+               log_very_verbose("Initialised segtype: %s", segtype->name);
+       }
+
+       return 1;
+}
index 332ae99e09330656899e3998364e82c9f5a8432f..f2a65eb82a972bac4201f17beb82653c7af7d705 100644 (file)
 #include "segtype.h"
 #include "display.h"
 #include "text_export.h"
-#include "text_import.h"
 #include "config.h"
-#include "str_list.h"
-#include "targets.h"
-#include "lvm-string.h"
 #include "activate.h"
-#include "str_list.h"
-#include "metadata.h"
 
 static const char *_unknown_name(const struct lv_segment *seg)
 {
@@ -32,17 +26,17 @@ static const char *_unknown_name(const struct lv_segment *seg)
        return seg->segtype->name;
 }
 
-static int _unknown_text_import(struct lv_segment *seg, const struct config_node *sn,
+static int _unknown_text_import(struct lv_segment *seg, const struct dm_config_node *sn,
                                struct dm_hash_table *pv_hash)
 {
-       struct config_node *new, *last = NULL, *head = NULL;
-       const struct config_node *current;
+       struct dm_config_node *new, *last = NULL, *head = NULL;
+       const struct dm_config_node *current;
        log_verbose("importing unknown segment");
        for (current = sn; current != NULL; current = current->sib) {
                if (!strcmp(current->key, "type") || !strcmp(current->key, "start_extent") ||
                    !strcmp(current->key, "tags") || !strcmp(current->key, "extent_count"))
                        continue;
-               new = clone_config_node(seg->lv->vg->vgmem, current, 0);
+               new = dm_config_clone_node_with_mem(seg->lv->vg->vgmem, current, 0);
                if (!new)
                        return_0;
                if (last)
@@ -57,7 +51,7 @@ static int _unknown_text_import(struct lv_segment *seg, const struct config_node
 
 static int _unknown_text_export(const struct lv_segment *seg, struct formatter *f)
 {
-       struct config_node *cn = seg->segtype_private;
+       struct dm_config_node *cn = seg->segtype_private;
        return out_config_node(f, cn);
 }
 
@@ -67,6 +61,7 @@ static int _unknown_add_target_line(struct dev_manager *dm __attribute__((unused
                                struct cmd_context *cmd __attribute__((unused)),
                                void **target_state __attribute__((unused)),
                                struct lv_segment *seg __attribute__((unused)),
+                               const struct lv_activate_opts *laopts __attribute__((unused)),
                                struct dm_tree_node *node, uint64_t len,
                                uint32_t *pvmove_mirror_count __attribute__((unused)))
 {
@@ -91,10 +86,12 @@ static struct segtype_handler _unknown_ops = {
 
 struct segment_type *init_unknown_segtype(struct cmd_context *cmd, const char *name)
 {
-       struct segment_type *segtype = dm_malloc(sizeof(*segtype));
+       struct segment_type *segtype = dm_zalloc(sizeof(*segtype));
 
-       if (!segtype)
-               return_NULL;
+       if (!segtype) {
+               log_error("Failed to allocate memory for unknown segtype");
+               return NULL;
+       }
 
        segtype->cmd = cmd;
        segtype->ops = &_unknown_ops;
index e85e852c4af48af83869ee6b7bed8f065f38da34..c85b822d7db2c4ad2de0a94c24257a8c9743730b 100644 (file)
@@ -125,6 +125,7 @@ static void _build_inverse(void)
        if (_built_inverse)
                return;
 
+       _built_inverse = 1;
        memset(_inverse_c, 0, sizeof(_inverse_c));
 
        for (ptr = _c; *ptr; ptr++)
@@ -157,7 +158,7 @@ int id_write_format(const struct id *id, char *buffer, size_t size)
 {
        int i, tot;
 
-       static unsigned group_size[] = { 6, 4, 4, 4, 4, 4, 6 };
+       static const unsigned group_size[] = { 6, 4, 4, 4, 4, 4, 6 };
 
        assert(ID_LEN == 32);
 
index 16ce66c40f504db8dd66a591b9385f772f9ca678..473daa0466c46be088bd438a13aacc249553d2a3 100644 (file)
 #include "toolcontext.h"
 #include "segtype.h"
 #include "display.h"
-#include "text_export.h"
-#include "text_import.h"
 #include "config.h"
 #include "str_list.h"
-#include "targets.h"
-#include "lvm-string.h"
 #include "activate.h"
-#include "metadata.h"
 
 static const char *_zero_name(const struct lv_segment *seg)
 {
@@ -44,6 +39,7 @@ static int _zero_add_target_line(struct dev_manager *dm __attribute__((unused)),
                                 struct cmd_context *cmd __attribute__((unused)),
                                 void **target_state __attribute__((unused)),
                                 struct lv_segment *seg __attribute__((unused)),
+                                const struct lv_activate_opts *laopts __attribute__((unused)),
                                 struct dm_tree_node *node,uint64_t len,
                                 uint32_t *pvmove_mirror_count __attribute__((unused)))
 {
@@ -96,7 +92,7 @@ static struct segtype_handler _zero_ops = {
 
 struct segment_type *init_zero_segtype(struct cmd_context *cmd)
 {
-       struct segment_type *segtype = dm_malloc(sizeof(*segtype));
+       struct segment_type *segtype = dm_zalloc(sizeof(*segtype));
 
        if (!segtype)
                return_NULL;
diff --git a/libdaemon/Makefile.in b/libdaemon/Makefile.in
new file mode 100644 (file)
index 0000000..dbe6516
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = @top_builddir@
+
+.PHONY: client server
+
+SUBDIRS += client
+
+ifeq ("@BUILD_LVMETAD@", "yes")
+  SUBDIRS += server
+server: client
+endif
+
+ifeq ($(MAKECMDGOALS),distclean)
+  SUBDIRS = client server
+endif
+
+include $(top_builddir)/make.tmpl
diff --git a/libdaemon/client/Makefile.in b/libdaemon/client/Makefile.in
new file mode 100644 (file)
index 0000000..d608816
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+#
+# This file is part of the device-mapper userspace tools.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU Lesser General Public License v.2.1.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = @top_builddir@
+
+LIB_STATIC = libdaemonclient.a
+SOURCES = daemon-io.c config-util.c daemon-client.c
+
+include $(top_builddir)/make.tmpl
diff --git a/libdaemon/client/config-util.c b/libdaemon/client/config-util.c
new file mode 100644 (file)
index 0000000..1c83134
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2011-2012 Red Hat, Inc.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "dm-logging.h"
+#include "config-util.h"
+#include "libdevmapper.h"
+
+int buffer_append_vf(struct buffer *buf, va_list ap)
+{
+       char *append;
+       char *next;
+       int keylen;
+       int64_t value;
+       char *string;
+       char *block;
+
+       while ((next = va_arg(ap, char *))) {
+               append = NULL;
+               if (!strchr(next, '=')) {
+                       log_error(INTERNAL_ERROR "Bad format string at '%s'", next);
+                       goto fail;
+               }
+               keylen = strchr(next, '=') - next;
+               if (strstr(next, "%d") || strstr(next, "%" PRId64)) {
+                       value = va_arg(ap, int64_t);
+                       if (dm_asprintf(&append, "%.*s= %" PRId64 "\n", keylen, next, value) < 0)
+                               goto fail;
+               } else if (strstr(next, "%s")) {
+                       string = va_arg(ap, char *);
+                       if (dm_asprintf(&append, "%.*s= \"%s\"\n", keylen, next, string) < 0)
+                               goto fail;
+               } else if (strstr(next, "%b")) {
+                       if (!(block = va_arg(ap, char *)))
+                               continue;
+                       if (dm_asprintf(&append, "%.*s%s", keylen, next, block) < 0)
+                               goto fail;
+               } else if (dm_asprintf(&append, "%s", next) < 0)
+                       goto fail;
+
+               if (!append ||
+                   !buffer_append(buf, append))
+                       goto fail;
+
+               dm_free(append);
+       }
+
+       return 1;
+fail:
+       dm_free(append);
+       return 0;
+}
+
+int buffer_append_f(struct buffer *buf, ...)
+{
+       int res;
+       va_list ap;
+
+       va_start(ap, buf);
+       res = buffer_append_vf(buf, ap);
+       va_end(ap);
+
+       return res;
+}
+
+int set_flag(struct dm_config_tree *cft, struct dm_config_node *parent,
+            const char *field, const char *flag, int want)
+{
+       struct dm_config_value *value = NULL, *pred = NULL;
+       struct dm_config_node *node = dm_config_find_node(parent->child, field);
+       struct dm_config_value *new;
+
+       if (node)
+               value = node->v;
+
+       while (value && value->type != DM_CFG_EMPTY_ARRAY && strcmp(value->v.str, flag)) {
+               pred = value;
+               value = value->next;
+       }
+
+       if (value && want)
+               return 1;
+
+       if (!value && !want)
+               return 1;
+
+       if (value && !want) {
+               if (pred) {
+                       pred->next = value->next;
+               } else if (value == node->v && value->next) {
+                       node->v = value->next;
+               } else {
+                       node->v->type = DM_CFG_EMPTY_ARRAY;
+               }
+       }
+
+       if (!value && want) {
+               if (!node) {
+                       if (!(node = dm_config_create_node(cft, field)))
+                               return 0;
+                       node->sib = parent->child;
+                       if (!(node->v = dm_config_create_value(cft)))
+                               return 0;
+                       node->v->type = DM_CFG_EMPTY_ARRAY;
+                       node->parent = parent;
+                       parent->child = node;
+               }
+               if (!(new = dm_config_create_value(cft))) {
+                       /* FIXME error reporting */
+                       return 0;
+               }
+               new->type = DM_CFG_STRING;
+               new->v.str = flag;
+               new->next = node->v;
+               node->v = new;
+       }
+
+       return 1;
+}
+
+static void chain_node(struct dm_config_node *cn,
+                      struct dm_config_node *parent,
+                      struct dm_config_node *pre_sib)
+{
+       cn->parent = parent;
+       cn->sib = NULL;
+
+       if (parent && parent->child && !pre_sib) { /* find the last one */
+               pre_sib = parent->child;
+               while (pre_sib && pre_sib->sib)
+                       pre_sib = pre_sib->sib;
+       }
+
+       if (parent && !parent->child)
+               parent->child = cn;
+       if (pre_sib) {
+               cn->sib = pre_sib->sib;
+               pre_sib->sib = cn;
+       }
+
+}
+
+struct dm_config_node *make_config_node(struct dm_config_tree *cft,
+                                       const char *key,
+                                       struct dm_config_node *parent,
+                                       struct dm_config_node *pre_sib)
+{
+       struct dm_config_node *cn;
+
+       if (!(cn = dm_config_create_node(cft, key)))
+               return NULL;
+
+       cn->v = NULL;
+       cn->child = NULL;
+
+       chain_node(cn, parent, pre_sib);
+
+       return cn;
+}
+
+struct dm_config_node *make_text_node(struct dm_config_tree *cft,
+                                     const char *key,
+                                     const char *value,
+                                     struct dm_config_node *parent,
+                                     struct dm_config_node *pre_sib)
+{
+       struct dm_config_node *cn;
+
+       if (!(cn = make_config_node(cft, key, parent, pre_sib)) ||
+           !(cn->v = dm_config_create_value(cft)))
+               return NULL;
+
+       cn->v->type = DM_CFG_STRING;
+       cn->v->v.str = value;
+       return cn;
+}
+
+struct dm_config_node *make_int_node(struct dm_config_tree *cft,
+                                    const char *key,
+                                    int64_t value,
+                                    struct dm_config_node *parent,
+                                    struct dm_config_node *pre_sib)
+{
+       struct dm_config_node *cn;
+
+       if (!(cn = make_config_node(cft, key, parent, pre_sib)) ||
+           !(cn->v = dm_config_create_value(cft)))
+               return NULL;
+
+       cn->v->type = DM_CFG_INT;
+       cn->v->v.i = value;
+       return cn;
+}
+
+struct dm_config_node *config_make_nodes_v(struct dm_config_tree *cft,
+                                          struct dm_config_node *parent,
+                                          struct dm_config_node *pre_sib,
+                                          va_list ap)
+{
+       const char *next;
+       struct dm_config_node *first = NULL;
+       struct dm_config_node *cn;
+       const char *fmt, *key;
+
+       while ((next = va_arg(ap, char *))) {
+               cn = NULL;
+               fmt = strchr(next, '=');
+
+               if (!fmt) {
+                       log_error(INTERNAL_ERROR "Bad format string '%s'", fmt);
+                       return_NULL;
+               }
+               fmt += 2;
+
+               key = dm_pool_strdup(cft->mem, next);
+               *strchr(key, '=') = 0;
+
+               if (!strcmp(fmt, "%d") || !strcmp(fmt, "%" PRId64)) {
+                       int64_t value = va_arg(ap, int64_t);
+                       if (!(cn = make_int_node(cft, key, value, parent, pre_sib)))
+                               return 0;
+               } else if (!strcmp(fmt, "%s")) {
+                       char *value = va_arg(ap, char *);
+                       if (!(cn = make_text_node(cft, key, value, parent, pre_sib)))
+                               return 0;
+               } else if (!strcmp(fmt, "%t")) {
+                       struct dm_config_tree *tree = va_arg(ap, struct dm_config_tree *);
+                       cn = dm_config_clone_node(cft, tree->root, 1);
+                       if (!cn)
+                               return 0;
+                       cn->key = key;
+                       chain_node(cn, parent, pre_sib);
+               } else {
+                       log_error(INTERNAL_ERROR "Bad format string '%s'", fmt);
+                       return_NULL;
+               }
+               if (!first)
+                       first = cn;
+               if (cn)
+                       pre_sib = cn;
+       }
+
+       return first;
+}
+
+struct dm_config_node *config_make_nodes(struct dm_config_tree *cft,
+                                        struct dm_config_node *parent,
+                                        struct dm_config_node *pre_sib,
+                                        ...)
+{
+       struct dm_config_node *res;
+       va_list ap;
+
+       va_start(ap, pre_sib);
+       res = config_make_nodes_v(cft, parent, pre_sib, ap);
+       va_end(ap);
+
+       return res;
+}
+
+int buffer_realloc(struct buffer *buf, int needed)
+{
+       char *new;
+       int alloc = buf->allocated;
+       if (alloc < needed)
+               alloc = needed;
+
+       buf->allocated += alloc;
+       new = realloc(buf->mem, buf->allocated);
+       if (new)
+               buf->mem = new;
+       else { /* utter failure */
+               dm_free(buf->mem);
+               buf->mem = 0;
+               buf->allocated = buf->used = 0;
+               return 0;
+       }
+       return 1;
+}
+
+int buffer_append(struct buffer *buf, const char *string)
+{
+       int len = strlen(string);
+
+       if ((buf->allocated - buf->used <= len) &&
+           !buffer_realloc(buf, len + 1))
+                return 0;
+
+       strcpy(buf->mem + buf->used, string);
+       buf->used += len;
+       return 1;
+}
+
+int buffer_line(const char *line, void *baton)
+{
+       struct buffer *buf = baton;
+       if (!buffer_append(buf, line))
+               return 0;
+       if (!buffer_append(buf, "\n"))
+               return 0;
+       return 1;
+}
+
+void buffer_destroy(struct buffer *buf)
+{
+       dm_free(buf->mem);
+       buffer_init(buf);
+}
+
+void buffer_init(struct buffer *buf)
+{
+       buf->allocated = buf->used = 0;
+       buf->mem = 0;
+}
diff --git a/libdaemon/client/config-util.h b/libdaemon/client/config-util.h
new file mode 100644 (file)
index 0000000..f03bcab
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011-2012 Red Hat, Inc.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LVM_DAEMON_CONFIG_UTIL_H
+#define _LVM_DAEMON_CONFIG_UTIL_H
+
+#include "configure.h"
+#include "libdevmapper.h"
+
+#include <stdarg.h>
+
+struct buffer {
+       int allocated;
+       int used;
+       char *mem;
+};
+
+int buffer_append_vf(struct buffer *buf, va_list ap);
+int buffer_append_f(struct buffer *buf, ...);
+int buffer_append(struct buffer *buf, const char *string);
+void buffer_init(struct buffer *buf);
+void buffer_destroy(struct buffer *buf);
+int buffer_realloc(struct buffer *buf, int required);
+
+int buffer_line(const char *line, void *baton);
+
+int set_flag(struct dm_config_tree *cft, struct dm_config_node *parent,
+            const char *field, const char *flag, int want);
+
+struct dm_config_node *make_config_node(struct dm_config_tree *cft,
+                                       const char *key,
+                                       struct dm_config_node *parent,
+                                       struct dm_config_node *pre_sib);
+
+struct dm_config_node *make_text_node(struct dm_config_tree *cft,
+                                     const char *key,
+                                     const char *value,
+                                     struct dm_config_node *parent,
+                                     struct dm_config_node *pre_sib);
+
+struct dm_config_node *make_int_node(struct dm_config_tree *cft,
+                                    const char *key,
+                                    int64_t value,
+                                    struct dm_config_node *parent,
+                                    struct dm_config_node *pre_sib);
+
+struct dm_config_node *config_make_nodes_v(struct dm_config_tree *cft,
+                                          struct dm_config_node *parent,
+                                          struct dm_config_node *pre_sib,
+                                          va_list ap);
+struct dm_config_node *config_make_nodes(struct dm_config_tree *cft,
+                                        struct dm_config_node *parent,
+                                        struct dm_config_node *pre_sib,
+                                        ...);
+
+#endif /* _LVM_DAEMON_SHARED_H */
diff --git a/libdaemon/client/daemon-client.c b/libdaemon/client/daemon-client.c
new file mode 100644 (file)
index 0000000..a010cc0
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2011-2012 Red Hat, Inc.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "daemon-io.h"
+#include "config-util.h"
+#include "daemon-client.h"
+#include "dm-logging.h"
+
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h> // ENOMEM
+
+daemon_handle daemon_open(daemon_info i) {
+       daemon_handle h = { .protocol_version = 0, .error = 0 };
+       daemon_reply r = { .cft = NULL };
+       struct sockaddr_un sockaddr = { .sun_family = AF_UNIX };
+
+       if ((h.socket_fd = socket(PF_UNIX, SOCK_STREAM /* | SOCK_NONBLOCK */, 0)) < 0)
+               goto error;
+
+       if (!dm_strncpy(sockaddr.sun_path, i.socket, sizeof(sockaddr.sun_path))) {
+               fprintf(stderr, "%s: daemon socket path too long.\n", i.socket);
+               goto error;
+       }
+
+       if (connect(h.socket_fd,(struct sockaddr *) &sockaddr, sizeof(sockaddr)))
+               goto error;
+
+       r = daemon_send_simple(h, "hello", NULL);
+       if (r.error || strcmp(daemon_reply_str(r, "response", "unknown"), "OK"))
+               goto error;
+
+       h.protocol = daemon_reply_str(r, "protocol", NULL);
+       if (h.protocol)
+               h.protocol = dm_strdup(h.protocol); /* keep around */
+       h.protocol_version = daemon_reply_int(r, "version", 0);
+
+       if (i.protocol && (!h.protocol || strcmp(h.protocol, i.protocol)))
+               goto error;
+       if (i.protocol_version && h.protocol_version != i.protocol_version)
+               goto error;
+
+       daemon_reply_destroy(r);
+       return h;
+
+error:
+       h.error = errno;
+       if (h.socket_fd >= 0)
+               if (close(h.socket_fd))
+                       log_sys_error("close", "daemon_open");
+       if (r.cft)
+               daemon_reply_destroy(r);
+       h.socket_fd = -1;
+       return h;
+}
+
+daemon_reply daemon_send(daemon_handle h, daemon_request rq)
+{
+       struct buffer buffer;
+       daemon_reply reply = { .cft = NULL, .error = 0 };
+       assert(h.socket_fd >= 0);
+       buffer = rq.buffer;
+
+       if (!buffer.mem)
+               dm_config_write_node(rq.cft->root, buffer_line, &buffer);
+
+       assert(buffer.mem);
+       if (!buffer_write(h.socket_fd, &buffer))
+               reply.error = errno;
+
+       if (buffer_read(h.socket_fd, &reply.buffer)) {
+               reply.cft = dm_config_from_string(reply.buffer.mem);
+               if (!reply.cft)
+                       reply.error = EPROTO;
+       } else
+               reply.error = errno;
+
+       if (buffer.mem != rq.buffer.mem)
+               buffer_destroy(&buffer);
+
+       return reply;
+}
+
+void daemon_reply_destroy(daemon_reply r) {
+       if (r.cft)
+               dm_config_destroy(r.cft);
+       buffer_destroy(&r.buffer);
+}
+
+daemon_reply daemon_send_simple_v(daemon_handle h, const char *id, va_list ap)
+{
+       static const daemon_reply err = { .error = ENOMEM, .buffer = { 0, 0, NULL }, .cft = NULL };
+       daemon_request rq = { .cft = NULL };
+       daemon_reply repl;
+
+       if (!buffer_append_f(&rq.buffer, "request = %s", id, NULL) ||
+           !buffer_append_vf(&rq.buffer, ap)) {
+               buffer_destroy(&rq.buffer);
+               return err;
+       }
+
+       repl = daemon_send(h, rq);
+       buffer_destroy(&rq.buffer);
+
+       return repl;
+}
+
+daemon_reply daemon_send_simple(daemon_handle h, const char *id, ...)
+{
+       daemon_reply r;
+       va_list ap;
+
+       va_start(ap, id);
+       r = daemon_send_simple_v(h, id, ap);
+       va_end(ap);
+
+       return r;
+}
+
+void daemon_close(daemon_handle h)
+{
+       dm_free((char *)h.protocol);
+}
+
+daemon_request daemon_request_make(const char *id)
+{
+       daemon_request r;
+       r.cft = NULL;
+       buffer_init(&r.buffer);
+
+       if (!(r.cft = dm_config_create()))
+               goto bad;
+
+       if (!(r.cft->root = make_text_node(r.cft, "request", id, NULL, NULL)))
+               goto bad;
+
+       return r;
+bad:
+       if (r.cft)
+               dm_config_destroy(r.cft);
+       r.cft = NULL;
+       return r;
+}
+
+int daemon_request_extend_v(daemon_request r, va_list ap)
+{
+       if (!r.cft)
+               return 0;
+
+       if (!config_make_nodes_v(r.cft, NULL, r.cft->root, ap))
+               return 0;
+
+       return 1;
+}
+
+int daemon_request_extend(daemon_request r, ...)
+{
+       int res;
+       va_list ap;
+
+       va_start(ap, r);
+       res = daemon_request_extend_v(r, ap);
+       va_end(ap);
+
+       return res;
+}
+
+void daemon_request_destroy(daemon_request r) {
+       if (r.cft)
+               dm_config_destroy(r.cft);
+       buffer_destroy(&r.buffer);
+}
+
diff --git a/libdaemon/client/daemon-client.h b/libdaemon/client/daemon-client.h
new file mode 100644 (file)
index 0000000..6ba65e6
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2011-2012 Red Hat, Inc.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LVM_DAEMON_COMMON_CLIENT_H
+#define _LVM_DAEMON_COMMON_CLIENT_H
+
+#include "libdevmapper.h"
+#include "config-util.h"
+
+typedef struct {
+       int socket_fd; /* the fd we use to talk to the daemon */
+       const char *protocol;
+       int protocol_version;  /* version of the protocol the daemon uses */
+       int error;
+} daemon_handle;
+
+typedef struct {
+       const char *path; /* the binary of the daemon */
+       const char *socket; /* path to the comms socket */
+       unsigned autostart:1; /* start the daemon if not running? */
+
+       /*
+        * If the following are not NULL/0, an attempt to talk to a daemon which
+        * uses a different protocol or version will fail.
+        */
+       const char *protocol;
+       int protocol_version;
+} daemon_info;
+
+typedef struct {
+       struct buffer buffer;
+       /*
+        * The request looks like this:
+        *    request = "id"
+        *    arg_foo = "something"
+        *    arg_bar = 3
+        *    arg_wibble {
+        *        something_special = "here"
+        *        amount = 75
+        *        knobs = [ "twiddle", "tweak" ]
+        *    }
+        */
+       struct dm_config_tree *cft;
+} daemon_request;
+
+typedef struct {
+       int error; /* 0 for success */
+       struct buffer buffer;
+       struct dm_config_tree *cft; /* parsed reply, if available */
+} daemon_reply;
+
+/*
+ * Open the communication channel to the daemon. If the daemon is not running,
+ * it may be autostarted based on the binary path provided in the info (this
+ * will only happen if autostart is set to true). If the call fails for any
+ * reason, daemon_handle_valid(h) for the response will return false. Otherwise,
+ * the connection is good to start serving requests.
+ */
+daemon_handle daemon_open(daemon_info i);
+
+/*
+ * Send a request to the daemon, waiting for the reply. All communication with
+ * the daemon is synchronous. The function handles the IO details and parses the
+ * response, handling common error conditions. See "daemon_reply" for details.
+ *
+ * In case the request contains a non-NULL buffer pointer, this buffer is sent
+ * *verbatim* to the server. In this case, the cft pointer may be NULL (but will
+ * be ignored even if non-NULL). If the buffer is NULL, the cft is required to
+ * be a valid pointer, and is used to build up the request.
+ */
+daemon_reply daemon_send(daemon_handle h, daemon_request r);
+
+/*
+ * A simple interface to daemon_send. This function just takes the command id
+ * and possibly a list of parameters (of the form "name = %?", "value"). The
+ * type (string, integer) of the value is indicated by a character substituted
+ * for ? in %?: d for integer, s for string.
+ */
+daemon_reply daemon_send_simple(daemon_handle h, const char *id, ...);
+daemon_reply daemon_send_simple_v(daemon_handle h, const char *id, va_list ap);
+
+daemon_request daemon_request_make(const char *id);
+int daemon_request_extend(daemon_request r, ...);
+int daemon_request_extend_v(daemon_request r, va_list ap);
+void daemon_request_destroy(daemon_request r);
+
+void daemon_reply_destroy(daemon_reply r);
+
+static inline int64_t daemon_reply_int(daemon_reply r, const char *path, int64_t def) {
+       return dm_config_find_int64(r.cft->root, path, def);
+}
+
+static inline const char *daemon_reply_str(daemon_reply r, const char *path, const char *def) {
+       return dm_config_find_str(r.cft->root, path, def);
+}
+
+
+/* Shut down the communication to the daemon. Compulsory. */
+void daemon_close(daemon_handle h);
+
+#endif
diff --git a/libdaemon/client/daemon-io.c b/libdaemon/client/daemon-io.c
new file mode 100644 (file)
index 0000000..37f2744
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2011-2012 Red Hat, Inc.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "daemon-io.h"
+#include "libdevmapper.h"
+
+/*
+ * Read a single message from a (socket) filedescriptor. Messages are delimited
+ * by blank lines. This call will block until all of a message is received. The
+ * memory will be allocated from heap. Upon error, all memory is freed and the
+ * buffer pointer is set to NULL.
+ *
+ * See also write_buffer about blocking (read_buffer has identical behaviour).
+ */
+int buffer_read(int fd, struct buffer *buffer) {
+       if (!buffer_realloc(buffer, 32)) /* ensure we have some space */
+               goto fail;
+
+       while (1) {
+               int result = read(fd, buffer->mem + buffer->used, buffer->allocated - buffer->used);
+               if (result > 0) {
+                       buffer->used += result;
+                       if (!strncmp((buffer->mem) + buffer->used - 4, "\n##\n", 4)) {
+                               *(buffer->mem + buffer->used - 4) = 0;
+                               buffer->used -= 4;
+                               break; /* success, we have the full message now */
+                       }
+                       if (buffer->used - buffer->allocated < 32)
+                               if (!buffer_realloc(buffer, 1024))
+                                       goto fail;
+                       continue;
+               }
+               if (result == 0) {
+                       errno = ECONNRESET;
+                       goto fail; /* we should never encounter EOF here */
+               }
+               if (result < 0 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
+                       goto fail;
+               /* TODO call select here if we encountered EAGAIN/EWOULDBLOCK/EINTR */
+       }
+       return 1;
+fail:
+       return 0;
+}
+
+/*
+ * Write a buffer to a filedescriptor. Keep trying. Blocks (even on
+ * SOCK_NONBLOCK) until all of the write went through.
+ *
+ * TODO use select on EWOULDBLOCK/EAGAIN/EINTR to avoid useless spinning
+ */
+int buffer_write(int fd, struct buffer *buffer) {
+       struct buffer terminate = { .mem = (char *) "\n##\n", .used = 4 };
+       int done = 0;
+       int written = 0;
+       struct buffer *use = buffer;
+write:
+       while (1) {
+               int result = write(fd, use->mem + written, use->used - written);
+               if (result > 0)
+                       written += result;
+               if (result < 0 && errno != EWOULDBLOCK && errno != EAGAIN && errno != EINTR)
+                       return 0; /* too bad */
+               if (written == use->used) {
+                       if (done)
+                               return 1;
+                       else
+                               break; /* done */
+               }
+       }
+
+       use = &terminate;
+       written = 0;
+       done = 1;
+       goto write;
+}
diff --git a/libdaemon/client/daemon-io.h b/libdaemon/client/daemon-io.h
new file mode 100644 (file)
index 0000000..1f55af7
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011-2012 Red Hat, Inc.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LVM_DAEMON_IO_H
+#define _LVM_DAEMON_IO_H
+
+#include "configure.h"
+#include "config-util.h"
+#include "libdevmapper.h"
+
+#define _REENTRANT
+#define _GNU_SOURCE
+#define _FILE_OFFSET_BITS 64
+
+/* TODO function names */
+
+int buffer_read(int fd, struct buffer *buffer);
+int buffer_write(int fd, struct buffer *buffer);
+
+#endif /* _LVM_DAEMON_SHARED_H */
diff --git a/libdaemon/server/Makefile.in b/libdaemon/server/Makefile.in
new file mode 100644 (file)
index 0000000..1c4a38e
--- /dev/null
@@ -0,0 +1,22 @@
+# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+#
+# This file is part of the device-mapper userspace tools.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU Lesser General Public License v.2.1.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = @top_builddir@
+
+LIB_STATIC = libdaemonserver.a
+SOURCES = daemon-server.c daemon-log.c
+
+include $(top_builddir)/make.tmpl
+
+LIBS += $(DAEMON_LIBS)
diff --git a/libdaemon/server/daemon-log.c b/libdaemon/server/daemon-log.c
new file mode 100644 (file)
index 0000000..6f5f4dc
--- /dev/null
@@ -0,0 +1,180 @@
+#include "daemon-server.h"
+#include "daemon-log.h"
+#include <syslog.h>
+#include <assert.h>
+
+struct backend {
+       int id;
+       void (*log)(log_state *s, void **state, int type, const char *message);
+};
+
+static void log_syslog(log_state *s, void **state, int type, const char *message)
+{
+       int prio;
+
+       if (!*state) { /* initialize */
+               *state = (void *)1;
+               openlog(s->name, LOG_PID, LOG_DAEMON);
+       }
+
+       switch (type) {
+       case DAEMON_LOG_INFO: prio = LOG_INFO; break;
+       case DAEMON_LOG_WARN: prio = LOG_WARNING; break;
+       case DAEMON_LOG_FATAL: prio = LOG_CRIT; break;
+       default: prio = LOG_DEBUG; break;
+       }
+
+       syslog(prio, "%s", message);
+}
+
+static void log_stderr(log_state *s, void **state, int type, const char *message)
+{
+       const char *prefix;
+
+       switch (type) {
+       case DAEMON_LOG_INFO: prefix = "I: "; break;
+       case DAEMON_LOG_WARN: prefix = "W: " ; break;
+       case DAEMON_LOG_ERROR: /* fall through */
+       case DAEMON_LOG_FATAL: prefix = "E: " ; break;
+       default: prefix = ""; break;
+       }
+
+       fprintf(stderr, "%s%s\n", prefix, message);
+}
+
+struct backend backend[] = {
+       { DAEMON_LOG_OUTLET_SYSLOG, log_syslog },
+       { DAEMON_LOG_OUTLET_STDERR, log_stderr },
+       { 0, 0 }
+};
+
+void daemon_log(log_state *s, int type, const char *message) {
+       int i = 0;
+       while ( backend[i].id ) {
+               if ( (s->log_config[type] & backend[i].id) == backend[i].id )
+                       backend[i].log( s, &s->backend_state[i], type, message );
+               ++ i;
+       }
+}
+
+static int _type_interesting(log_state *s, int type) {
+       int i = 0;
+       while ( backend[i].id ) {
+               if ( (s->log_config[type] & backend[i].id) == backend[i].id )
+                       return 1;
+               ++ i;
+       }
+       return 0;
+}
+
+void daemon_logf(log_state *s, int type, const char *fmt, ...) {
+       char *buf;
+       va_list ap;
+
+       va_start(ap, fmt);
+       if (dm_vasprintf(&buf, fmt, ap) >= 0) {
+               daemon_log(s, type, buf);
+               dm_free(buf);
+       } /* else return_0 */
+       va_end(ap);
+}
+
+struct log_line_baton {
+       log_state *s;
+       int type;
+       const char *prefix;
+};
+
+static int _log_line(const char *line, void *baton) {
+       struct log_line_baton *b = baton;
+       daemon_logf(b->s, b->type, "%s%s", b->prefix, line);
+       return 0;
+}
+
+void daemon_log_cft(log_state *s, int type, const char *prefix, const struct dm_config_node *n)
+{
+       struct log_line_baton b = { .s = s, .type = type, .prefix = prefix };
+
+       if (!_type_interesting(s, type))
+               return;
+
+       dm_config_write_node(n, &_log_line, &b);
+}
+
+void daemon_log_multi(log_state *s, int type, const char *prefix, const char *msg)
+{
+       struct log_line_baton b = { .s = s, .type = type, .prefix = prefix };
+       char *buf;
+       char *pos;
+
+       if (!_type_interesting(s, type))
+               return;
+
+       buf = dm_strdup(msg);
+       pos = buf;
+
+       if (!buf)
+               return; /* _0 */
+
+       while (pos) {
+               char *next = strchr(pos, '\n');
+               if (next)
+                       *next = 0;
+               _log_line(pos, &b);
+               pos = next ? next + 1 : 0;
+       }
+       dm_free(buf);
+}
+
+void daemon_log_enable(log_state *s, int outlet, int type, int enable)
+{
+       assert(type < 32);
+       if (enable)
+               s->log_config[type] |= outlet;
+       else
+               s->log_config[type] &= ~outlet;
+}
+
+static int _parse_one(log_state *s, int outlet, const char *type, int enable)
+{
+       int i;
+       if (!strcmp(type, "all"))
+               for (i = 0; i < 32; ++i)
+                       daemon_log_enable(s, outlet, i, enable);
+       else if (!strcmp(type, "wire"))
+               daemon_log_enable(s, outlet, DAEMON_LOG_WIRE, enable);
+       else if (!strcmp(type, "debug"))
+               daemon_log_enable(s, outlet, DAEMON_LOG_DEBUG, enable);
+       else
+               return 0;
+
+       return 1;
+}
+
+int daemon_log_parse(log_state *s, int outlet, const char *types, int enable)
+{
+       char *buf;
+       char *pos;
+
+       if (!types || !types[0])
+               return 1;
+
+       if (!(buf = dm_strdup(types)))
+               return 0;
+
+       pos = buf;
+       while (pos) {
+               char *next = strchr(pos, ',');
+               if (next)
+                       *next = 0;
+               if (!_parse_one(s, outlet, pos, enable)) {
+                       dm_free(buf);
+                       return 0;
+               }
+               pos = next ? next + 1 : 0;
+       }
+
+       dm_free(buf);
+
+       return 1;
+}
diff --git a/libdaemon/server/daemon-log.h b/libdaemon/server/daemon-log.h
new file mode 100644 (file)
index 0000000..e2e11c5
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LVM_DAEMON_LOG_H
+#define _LVM_DAEMON_LOG_H
+
+enum { DAEMON_LOG_FATAL = 0 /* usually preceding daemon death */
+     , DAEMON_LOG_ERROR = 1 /* something serious has happened */
+     , DAEMON_LOG_WARN = 2 /* something unusual has happened */
+     , DAEMON_LOG_INFO = 3 /* thought you might be interested */
+     , DAEMON_LOG_WIRE = 4 /* dump traffic on client sockets */
+     , DAEMON_LOG_DEBUG = 5 /* unsorted debug stuff */
+};
+
+#define DEBUGLOG(s, x...) daemon_logf((s)->log, DAEMON_LOG_DEBUG, x)
+#define DEBUGLOG_cft(s, i, n) daemon_log_cft((s)->log, DAEMON_LOG_DEBUG, i, n)
+#define WARN(s, x...) daemon_logf((s)->log, DAEMON_LOG_WARN, x)
+#define INFO(s, x...) daemon_logf((s)->log, DAEMON_LOG_INFO, x)
+#define ERROR(s, x...) daemon_logf((s)->log, DAEMON_LOG_ERROR, x)
+#define FATAL(s, x...) daemon_logf((s)->log, DAEMON_LOG_FATAL, x)
+
+#endif
diff --git a/libdaemon/server/daemon-server.c b/libdaemon/server/daemon-server.c
new file mode 100644 (file)
index 0000000..3711419
--- /dev/null
@@ -0,0 +1,539 @@
+/*
+ * Copyright (C) 2011-2012 Red Hat, Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "daemon-io.h"
+#include "config-util.h"
+#include "daemon-server.h"
+#include "daemon-log.h"
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <syslog.h> /* FIXME. For the global closelog(). */
+
+#if 0
+/* Create a device monitoring thread. */
+static int _pthread_create(pthread_t *t, void *(*fun)(void *), void *arg, int stacksize)
+{
+       pthread_attr_t attr;
+       pthread_attr_init(&attr);
+       /*
+        * We use a smaller stack since it gets preallocated in its entirety
+        */
+       pthread_attr_setstacksize(&attr, stacksize);
+       return pthread_create(t, &attr, fun, arg);
+}
+#endif
+
+static volatile sig_atomic_t _shutdown_requested = 0;
+static int _systemd_activation = 0;
+
+static void _exit_handler(int sig __attribute__((unused)))
+{
+       _shutdown_requested = 1;
+}
+
+#ifdef linux
+
+#include <stddef.h>
+
+/*
+ * Kernel version 2.6.36 and higher has
+ * new OOM killer adjustment interface.
+ */
+#  define OOM_ADJ_FILE_OLD "/proc/self/oom_adj"
+#  define OOM_ADJ_FILE "/proc/self/oom_score_adj"
+
+/* From linux/oom.h */
+/* Old interface */
+#  define OOM_DISABLE (-17)
+#  define OOM_ADJUST_MIN (-16)
+/* New interface */
+#  define OOM_SCORE_ADJ_MIN (-1000)
+
+/* Systemd on-demand activation support */
+#  define SD_ACTIVATION_ENV_VAR_NAME "SD_ACTIVATION"
+#  define SD_LISTEN_PID_ENV_VAR_NAME "LISTEN_PID"
+#  define SD_LISTEN_FDS_ENV_VAR_NAME "LISTEN_FDS"
+#  define SD_LISTEN_FDS_START 3
+#  define SD_FD_SOCKET_SERVER SD_LISTEN_FDS_START
+
+#  include <stdio.h>
+
+static int _set_oom_adj(const char *oom_adj_path, int val)
+{
+       FILE *fp;
+
+       if (!(fp = fopen(oom_adj_path, "w"))) {
+               perror("oom_adj: fopen failed");
+               return 0;
+       }
+
+       fprintf(fp, "%i", val);
+
+       if (dm_fclose(fp))
+               perror("oom_adj: fclose failed");
+
+       return 1;
+}
+
+/*
+ * Protection against OOM killer if kernel supports it
+ */
+static int _protect_against_oom_killer(void)
+{
+       struct stat st;
+
+       if (stat(OOM_ADJ_FILE, &st) == -1) {
+               if (errno != ENOENT)
+                       perror(OOM_ADJ_FILE ": stat failed");
+
+               /* Try old oom_adj interface as a fallback */
+               if (stat(OOM_ADJ_FILE_OLD, &st) == -1) {
+                       if (errno == ENOENT)
+                               perror(OOM_ADJ_FILE_OLD " not found");
+                       else
+                               perror(OOM_ADJ_FILE_OLD ": stat failed");
+                       return 1;
+               }
+
+               return _set_oom_adj(OOM_ADJ_FILE_OLD, OOM_DISABLE) ||
+                      _set_oom_adj(OOM_ADJ_FILE_OLD, OOM_ADJUST_MIN);
+       }
+
+       return _set_oom_adj(OOM_ADJ_FILE, OOM_SCORE_ADJ_MIN);
+}
+
+union sockaddr_union {
+       struct sockaddr sa;
+       struct sockaddr_un un;
+};
+
+static int _handle_preloaded_socket(int fd, const char *path)
+{
+       struct stat st_fd;
+       union sockaddr_union sockaddr = { .sa.sa_family = 0 };
+       int type = 0;
+       socklen_t len = sizeof(type);
+       size_t path_len = strlen(path);
+
+       if (fd < 0)
+               return 0;
+
+       if (fstat(fd, &st_fd) < 0 || !S_ISSOCK(st_fd.st_mode))
+               return 0;
+
+       if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0 ||
+           len != sizeof(type) || type != SOCK_STREAM)
+               return 0;
+
+       len = sizeof(sockaddr);
+       if (getsockname(fd, &sockaddr.sa, &len) < 0 ||
+           len < sizeof(sa_family_t) ||
+           sockaddr.sa.sa_family != PF_UNIX)
+               return 0;
+
+       if (!(len >= offsetof(struct sockaddr_un, sun_path) + path_len + 1 &&
+             memcmp(path, sockaddr.un.sun_path, path_len) == 0))
+               return 0;
+
+       return 1;
+}
+
+static int _systemd_handover(struct daemon_state *ds)
+{
+       const char *e;
+       char *p;
+       unsigned long env_pid, env_listen_fds;
+       int r = 0;
+
+       /* SD_ACTIVATION must be set! */
+       if (!(e = getenv(SD_ACTIVATION_ENV_VAR_NAME)) || strcmp(e, "1"))
+               goto out;
+
+       /* LISTEN_PID must be equal to our PID! */
+       if (!(e = getenv(SD_LISTEN_PID_ENV_VAR_NAME)))
+               goto out;
+
+       errno = 0;
+       env_pid = strtoul(e, &p, 10);
+       if (errno || !p || *p || env_pid <= 0 ||
+           getpid() != (pid_t) env_pid)
+               goto out;
+
+       /* LISTEN_FDS must be 1 and the fd must be a socket! */
+       if (!(e = getenv(SD_LISTEN_FDS_ENV_VAR_NAME)))
+               goto out;
+
+       errno = 0;
+       env_listen_fds = strtoul(e, &p, 10);
+       if (errno || !p || *p || env_listen_fds != 1)
+               goto out;
+
+       /* Check and handle the socket passed in */
+       if ((r = _handle_preloaded_socket(SD_FD_SOCKET_SERVER, ds->socket_path)))
+               ds->socket_fd = SD_FD_SOCKET_SERVER;
+
+out:
+       unsetenv(SD_ACTIVATION_ENV_VAR_NAME);
+       unsetenv(SD_LISTEN_PID_ENV_VAR_NAME);
+       unsetenv(SD_LISTEN_FDS_ENV_VAR_NAME);
+       return r;
+}
+
+#endif
+
+static int _open_socket(daemon_state s)
+{
+       int fd = -1;
+       struct sockaddr_un sockaddr = { .sun_family = AF_UNIX };
+       mode_t old_mask;
+
+       (void) dm_prepare_selinux_context(s.socket_path, S_IFSOCK);
+       old_mask = umask(0077);
+
+       /* Open local socket */
+       fd = socket(PF_UNIX, SOCK_STREAM, 0);
+       if (fd < 0) {
+               perror("Can't create local socket.");
+               goto error;
+       }
+
+       /* Set Close-on-exec & non-blocking */
+       if (fcntl(fd, F_SETFD, 1))
+               fprintf(stderr, "setting CLOEXEC on socket fd %d failed: %s\n", fd, strerror(errno));
+       if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK))
+               fprintf(stderr, "setting O_NONBLOCK on socket fd %d failed: %s\n", fd, strerror(errno));
+
+       fprintf(stderr, "[D] creating %s\n", s.socket_path);
+       if (!dm_strncpy(sockaddr.sun_path, s.socket_path, sizeof(sockaddr.sun_path))) {
+               fprintf(stderr, "%s: daemon socket path too long.\n", s.socket_path);
+               goto error;
+       }
+
+       if (bind(fd, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) {
+               perror("can't bind local socket.");
+               goto error;
+       }
+       if (listen(fd, 1) != 0) {
+               perror("listen local");
+               goto error;
+       }
+
+out:
+       umask(old_mask);
+       (void) dm_prepare_selinux_context(NULL, 0);
+       return fd;
+
+error:
+       if (fd >= 0) {
+               if (close(fd))
+                       perror("close failed");
+               if (unlink(s.socket_path))
+                       perror("unlink failed");
+               fd = -1;
+       }
+       goto out;
+}
+
+static void remove_lockfile(const char *file)
+{
+       if (unlink(file))
+               perror("unlink failed");
+}
+
+static void _daemonise(void)
+{
+       int child_status;
+       int fd;
+       pid_t pid;
+       struct rlimit rlim;
+       struct timeval tval;
+       sigset_t my_sigset;
+
+       sigemptyset(&my_sigset);
+       if (sigprocmask(SIG_SETMASK, &my_sigset, NULL) < 0) {
+               fprintf(stderr, "Unable to restore signals.\n");
+               exit(EXIT_FAILURE);
+       }
+       signal(SIGTERM, &_exit_handler);
+
+       switch (pid = fork()) {
+       case -1:
+               perror("fork failed:");
+               exit(EXIT_FAILURE);
+
+       case 0:         /* Child */
+               break;
+
+       default:
+               /* Wait for response from child */
+               while (!waitpid(pid, &child_status, WNOHANG) && !_shutdown_requested) {
+                       tval.tv_sec = 0;
+                       tval.tv_usec = 250000;  /* .25 sec */
+                       select(0, NULL, NULL, NULL, &tval);
+               }
+
+               if (_shutdown_requested) /* Child has signaled it is ok - we can exit now */
+                       exit(0);
+
+               /* Problem with child.  Determine what it is by exit code */
+               fprintf(stderr, "Child exited with code %d\n", WEXITSTATUS(child_status));
+               exit(WEXITSTATUS(child_status));
+       }
+
+       if (chdir("/"))
+               exit(1);
+
+       if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
+               fd = 256; /* just have to guess */
+       else
+               fd = rlim.rlim_cur;
+
+       for (--fd; fd >= 0; fd--) {
+#ifdef linux
+               /* Do not close fds preloaded by systemd! */
+               if (_systemd_activation && fd == SD_FD_SOCKET_SERVER)
+                       continue;
+#endif
+               (void) close(fd);
+       }
+
+       if ((open("/dev/null", O_RDONLY) < 0) ||
+           (open("/dev/null", O_WRONLY) < 0) ||
+           (open("/dev/null", O_WRONLY) < 0))
+               exit(1);
+
+       setsid();
+}
+
+response daemon_reply_simple(const char *id, ...)
+{
+       va_list ap;
+       response res = { .cft = NULL };
+
+       va_start(ap, id);
+
+       buffer_init(&res.buffer);
+       if (!buffer_append_f(&res.buffer, "response = %s", id, NULL)) {
+               res.error = ENOMEM;
+               goto end;
+       }
+       if (!buffer_append_vf(&res.buffer, ap)) {
+               res.error = ENOMEM;
+               goto end;
+       }
+
+end:
+       va_end(ap);
+       return res;
+}
+
+struct thread_baton {
+       daemon_state s;
+       client_handle client;
+};
+
+static response builtin_handler(daemon_state s, client_handle h, request r)
+{
+       const char *rq = daemon_request_str(r, "request", "NONE");
+       response res = { .error = EPROTO };
+
+       if (!strcmp(rq, "hello")) {
+               return daemon_reply_simple("OK", "protocol = %s", s.protocol ?: "default",
+                                          "version = %" PRId64, (int64_t) s.protocol_version, NULL);
+       }
+
+       buffer_init(&res.buffer);
+       return res;
+}
+
+static void *client_thread(void *baton)
+{
+       struct thread_baton *b = baton;
+       request req;
+       response res;
+
+       buffer_init(&req.buffer);
+
+       while (1) {
+               if (!buffer_read(b->client.socket_fd, &req.buffer))
+                       goto fail;
+
+               req.cft = dm_config_from_string(req.buffer.mem);
+
+               if (!req.cft)
+                       fprintf(stderr, "error parsing request:\n %s\n", req.buffer.mem);
+               else
+                       daemon_log_cft(b->s.log, DAEMON_LOG_WIRE, "<- ", req.cft->root);
+
+               res = builtin_handler(b->s, b->client, req);
+
+               if (res.error == EPROTO) /* Not a builtin, delegate to the custom handler. */
+                       res = b->s.handler(b->s, b->client, req);
+
+               if (!res.buffer.mem) {
+                       dm_config_write_node(res.cft->root, buffer_line, &res.buffer);
+                       if (!buffer_append(&res.buffer, "\n\n"))
+                               goto fail;
+                       dm_config_destroy(res.cft);
+               }
+
+               if (req.cft)
+                       dm_config_destroy(req.cft);
+               buffer_destroy(&req.buffer);
+
+               daemon_log_multi(b->s.log, DAEMON_LOG_WIRE, "-> ", res.buffer.mem);
+               buffer_write(b->client.socket_fd, &res.buffer);
+
+               buffer_destroy(&res.buffer);
+       }
+fail:
+       /* TODO what should we really do here? */
+       if (close(b->client.socket_fd))
+               perror("close");
+       buffer_destroy(&req.buffer);
+       dm_free(baton);
+       return NULL;
+}
+
+static int handle_connect(daemon_state s)
+{
+       struct thread_baton *baton;
+       struct sockaddr_un sockaddr;
+       client_handle client = { .thread_id = 0 };
+       socklen_t sl = sizeof(sockaddr);
+
+       client.socket_fd = accept(s.socket_fd, (struct sockaddr *) &sockaddr, &sl);
+       if (client.socket_fd < 0)
+               return 0;
+
+       if (!(baton = malloc(sizeof(struct thread_baton))))
+               return 0;
+
+       baton->s = s;
+       baton->client = client;
+
+       if (pthread_create(&baton->client.thread_id, NULL, client_thread, baton))
+               return 0;
+
+       pthread_detach(baton->client.thread_id);
+
+       return 1;
+}
+
+void daemon_start(daemon_state s)
+{
+       int failed = 0;
+       log_state _log = { { 0 } };
+
+       /*
+        * Switch to C locale to avoid reading large locale-archive file used by
+        * some glibc (on some distributions it takes over 100MB). Some daemons
+        * need to use mlockall().
+        */
+       if (setenv("LANG", "C", 1))
+               perror("Cannot set LANG to C");
+
+#ifdef linux
+       _systemd_activation = _systemd_handover(&s);
+#endif
+
+       if (!s.foreground)
+               _daemonise();
+
+       s.log = &_log;
+       s.log->name = s.name;
+
+       /* Log important things to syslog by default. */
+       daemon_log_enable(s.log, DAEMON_LOG_OUTLET_SYSLOG, DAEMON_LOG_FATAL, 1);
+       daemon_log_enable(s.log, DAEMON_LOG_OUTLET_SYSLOG, DAEMON_LOG_ERROR, 1);
+
+       if (s.pidfile) {
+               (void) dm_prepare_selinux_context(s.pidfile, S_IFREG);
+
+               /*
+                * NB. Take care to not keep stale locks around. Best not exit(...)
+                * after this point.
+                */
+               if (dm_create_lockfile(s.pidfile) == 0)
+                       exit(1);
+
+               (void) dm_prepare_selinux_context(NULL, 0);
+       }
+
+       /* Set normal exit signals to request shutdown instead of dying. */
+       signal(SIGINT, &_exit_handler);
+       signal(SIGHUP, &_exit_handler);
+       signal(SIGQUIT, &_exit_handler);
+       signal(SIGTERM, &_exit_handler);
+       signal(SIGALRM, &_exit_handler);
+       signal(SIGPIPE, SIG_IGN);
+
+#ifdef linux
+       /* Systemd has adjusted oom killer for us already */
+       if (s.avoid_oom && !_systemd_activation && !_protect_against_oom_killer())
+               ERROR(&s, "Failed to protect against OOM killer");
+#endif
+
+       if (!_systemd_activation && s.socket_path) {
+               s.socket_fd = _open_socket(s);
+               if (s.socket_fd < 0)
+                       failed = 1;
+       }
+
+       /* Signal parent, letting them know we are ready to go. */
+       if (!s.foreground)
+               kill(getppid(), SIGTERM);
+
+       if (s.daemon_init)
+               if (!s.daemon_init(&s))
+                       failed = 1;
+
+       while (!_shutdown_requested && !failed) {
+               fd_set in;
+               FD_ZERO(&in);
+               FD_SET(s.socket_fd, &in);
+               if (select(FD_SETSIZE, &in, NULL, NULL, NULL) < 0 && errno != EINTR)
+                       perror("select error");
+               if (FD_ISSET(s.socket_fd, &in))
+                       if (!_shutdown_requested && !handle_connect(s))
+                               ERROR(&s, "Failed to handle a client connection.");
+       }
+
+       /* If activated by systemd, do not unlink the socket - systemd takes care of that! */
+       if (!_systemd_activation && s.socket_fd >= 0)
+               if (unlink(s.socket_path))
+                       perror("unlink error");
+
+       if (s.daemon_fini)
+               if (!s.daemon_fini(&s))
+                       failed = 1;
+
+       INFO(&s, "%s shutting down", s.name);
+
+       closelog(); /* FIXME */
+       if (s.pidfile)
+               remove_lockfile(s.pidfile);
+       if (failed)
+               exit(1);
+}
diff --git a/libdaemon/server/daemon-server.h b/libdaemon/server/daemon-server.h
new file mode 100644 (file)
index 0000000..f184853
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2011-2012 Red Hat, Inc.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LVM_DAEMON_COMMON_SERVER_H
+#define _LVM_DAEMON_COMMON_SERVER_H
+
+#include "daemon-client.h"
+
+typedef struct {
+       int socket_fd; /* the fd we use to talk to the client */
+       pthread_t thread_id;
+       char *read_buf;
+       void *private; /* this holds per-client state */
+} client_handle;
+
+typedef struct {
+       struct dm_config_tree *cft;
+       struct buffer buffer;
+} request;
+
+typedef struct {
+       int error;
+       struct dm_config_tree *cft;
+       struct buffer buffer;
+} response;
+
+struct daemon_state;
+
+/*
+ * Craft a simple reply, without the need to construct a config_tree. See
+ * daemon_send_simple in daemon-client.h for the description of the parameters.
+ */
+response daemon_reply_simple(const char *id, ...);
+
+static inline int daemon_request_int(request r, const char *path, int def) {
+       if (!r.cft)
+               return def;
+       return dm_config_find_int(r.cft->root, path, def);
+}
+
+static inline const char *daemon_request_str(request r, const char *path, const char *def) {
+       if (!r.cft)
+               return def;
+       return dm_config_find_str(r.cft->root, path, def);
+}
+
+/*
+ * The callback. Called once per request issued, in the respective client's
+ * thread. It is presented by a parsed request (in the form of a config tree).
+ * The output is a new config tree that is serialised and sent back to the
+ * client. The client blocks until the request processing is done and reply is
+ * sent.
+ */
+typedef response (*handle_request)(struct daemon_state s, client_handle h, request r);
+
+typedef struct {
+       uint32_t log_config[32];
+       void *backend_state[32];
+       const char *name;
+} log_state;
+
+typedef struct daemon_state {
+       /*
+        * The maximal stack size for individual daemon threads. This is
+        * essential for daemons that need to be locked into memory, since
+        * pthread's default is 10M per thread.
+        */
+       int thread_stack_size;
+
+       /* Flags & attributes affecting the behaviour of the daemon. */
+       unsigned avoid_oom:1;
+       unsigned foreground:1;
+       const char *name;
+       const char *pidfile;
+       const char *socket_path;
+       const char *protocol;
+       int protocol_version;
+
+       handle_request handler;
+       int (*daemon_init)(struct daemon_state *st);
+       int (*daemon_fini)(struct daemon_state *st);
+
+       /* Global runtime info maintained by the framework. */
+       int socket_fd;
+
+       log_state *log;
+       void *private; /* the global daemon state */
+} daemon_state;
+
+/*
+ * Start serving the requests. This does all the daemonisation, socket setup
+ * work and so on. This function takes over the process, and upon failure, it
+ * will terminate execution. It may be called at most once.
+ */
+void daemon_start(daemon_state s);
+
+/*
+ * Take over from an already running daemon. This function handles connecting
+ * to the running daemon and telling it we are going to take over. The takeover
+ * request may be customised by passing in a non-NULL request.
+ *
+ * The takeover sequence: the old daemon stops accepting new clients, then it
+ * waits until all current client connections are closed. When that happens, it
+ * serializes its current state and sends that as a reply, which is then
+ * returned by this function (therefore, this function won't return until the
+ * previous instance has shut down).
+ *
+ * The daemon, after calling daemon_takeover is expected to set up its
+ * daemon_state using the reply from this function and call daemon_start as
+ * usual.
+ */
+daemon_reply daemon_takeover(daemon_info i, daemon_request r);
+
+/* Call this to request a clean shutdown of the daemon. Async safe. */
+void daemon_stop(void);
+
+enum { DAEMON_LOG_OUTLET_SYSLOG = 1,
+       DAEMON_LOG_OUTLET_STDERR = 2,
+       DAEMON_LOG_OUTLET_SOCKET = 4 };
+
+/* Log a message of a given type. */
+void daemon_log(log_state *s, int type, const char *message);
+
+/* Log a config (sub)tree, using a given message type, each line prefixed with "prefix". */
+void daemon_log_cft(log_state *s, int type, const char *prefix,
+                    const struct dm_config_node *n);
+
+/* Log a multi-line block, prefixing each line with "prefix". */
+void daemon_log_multi(log_state *s, int type, const char *prefix, const char *message);
+
+/* Log a formatted message as "type". See also daemon-log.h. */
+void daemon_logf(log_state *s, int type, const char *format, ...);
+
+/*
+ * Configure log_state to send messages of type "type" to the log outlet
+ * "outlet", iff "enable" is true.
+ */
+void daemon_log_enable(log_state *s, int outlet, int type, int enable);
+
+/*
+ * Set up logging on a given outlet using a list of message types (comma
+ * separated) to log using that outlet. The list is expected to look like this,
+ * "all,wire,debug". Returns 0 upon encountering an unknown message type.
+ */
+int daemon_log_parse(log_state *s, int outlet, const char *types, int enable);
+
+#endif
index 70be30950ab8913b7189870c6895efc0cb412126..bddb0a089d6d3e392372344b047b0e650b48c5aa 100644 (file)
@@ -25,6 +25,7 @@ SOURCES =\
        libdm-deptree.c \
        libdm-string.c \
        libdm-report.c \
+       libdm-config.c \
        mm/dbg_malloc.c \
        mm/pool.c \
        regex/matcher.c \
@@ -33,6 +34,9 @@ SOURCES =\
        $(interface)/libdm-iface.c
 
 INCLUDES = -I$(srcdir)/$(interface) -I$(srcdir)
+ifeq ("@VALGRIND_POOL@", "yes")
+INCLUDES += @VALGRIND_CFLAGS@
+endif
 
 ifeq ("@STATIC_LINK@", "yes")
 LIB_STATIC = $(interface)/libdevmapper.a
index d4543df5b24bf96361c93328901f27b85e6289b3..30b4a97ade9a459d7d58b4a24ef87e1ddc546e41 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of the device-mapper userspace tools.
  *
@@ -133,7 +133,7 @@ void dm_hash_destroy(struct dm_hash_table *t)
        dm_free(t);
 }
 
-static struct dm_hash_node **_find(struct dm_hash_table *t, const char *key,
+static struct dm_hash_node **_find(struct dm_hash_table *t, const void *key,
                                   uint32_t len)
 {
        unsigned h = _hash(key, len) & (t->num_slots - 1);
@@ -150,15 +150,15 @@ static struct dm_hash_node **_find(struct dm_hash_table *t, const char *key,
        return c;
 }
 
-void *dm_hash_lookup_binary(struct dm_hash_table *t, const char *key,
-                        uint32_t len)
+void *dm_hash_lookup_binary(struct dm_hash_table *t, const void *key,
+                           uint32_t len)
 {
        struct dm_hash_node **c = _find(t, key, len);
 
        return *c ? (*c)->data : 0;
 }
 
-int dm_hash_insert_binary(struct dm_hash_table *t, const char *key,
+int dm_hash_insert_binary(struct dm_hash_table *t, const void *key,
                          uint32_t len, void *data)
 {
        struct dm_hash_node **c = _find(t, key, len);
@@ -180,7 +180,7 @@ int dm_hash_insert_binary(struct dm_hash_table *t, const char *key,
        return 1;
 }
 
-void dm_hash_remove_binary(struct dm_hash_table *t, const char *key,
+void dm_hash_remove_binary(struct dm_hash_table *t, const void *key,
                        uint32_t len)
 {
        struct dm_hash_node **c = _find(t, key, len);
diff --git a/libdm/ioctl/libdm-compat.h b/libdm/ioctl/libdm-compat.h
deleted file mode 100644 (file)
index 5ba63ce..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
- *
- * This file is part of the device-mapper userspace tools.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU Lesser General Public License v.2.1.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#ifndef _LINUX_LIBDM_COMPAT_H
-#define _LINUX_LIBDM_COMPAT_H
-
-#include "kdev_t.h"
-#include "dm-ioctl.h"
-#include <inttypes.h>
-#include <sys/ioctl.h>
-
-struct dm_task;
-struct dm_info;
-
-/*
- * Old versions of structures for backwards compatibility.
- */
-
-struct dm_ioctl_v1 {
-       uint32_t version[3];    /* in/out */
-       uint32_t data_size;     /* total size of data passed in
-                                * including this struct */
-
-       uint32_t data_start;    /* offset to start of data
-                                * relative to start of this struct */
-
-       int32_t target_count;   /* in/out */
-       int32_t open_count;     /* out */
-       uint32_t flags;         /* in/out */
-
-       __kernel_dev_t dev;     /* in/out */
-
-       char name[DM_NAME_LEN]; /* device name */
-       char uuid[DM_UUID_LEN]; /* unique identifier for
-                                * the block device */
-};
-
-struct dm_target_spec_v1 {
-       int32_t status;         /* used when reading from kernel only */
-       uint64_t sector_start;
-       uint32_t length;
-       uint32_t next;
-
-       char target_type[DM_MAX_TYPE_NAME];
-
-};
-
-struct dm_target_deps_v1 {
-       uint32_t count;
-
-       __kernel_dev_t dev[0];  /* out */
-};
-
-enum {
-       /* Top level cmds */
-       DM_VERSION_CMD_V1 = 0,
-       DM_REMOVE_ALL_CMD_V1,
-
-       /* device level cmds */
-       DM_DEV_CREATE_CMD_V1,
-       DM_DEV_REMOVE_CMD_V1,
-       DM_DEV_RELOAD_CMD_V1,
-       DM_DEV_RENAME_CMD_V1,
-       DM_DEV_SUSPEND_CMD_V1,
-       DM_DEV_DEPS_CMD_V1,
-       DM_DEV_STATUS_CMD_V1,
-
-       /* target level cmds */
-       DM_TARGET_STATUS_CMD_V1,
-       DM_TARGET_WAIT_CMD_V1,
-};
-
-#define DM_VERSION_V1       _IOWR(DM_IOCTL, DM_VERSION_CMD_V1, struct dm_ioctl)
-#define DM_REMOVE_ALL_V1    _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD_V1, struct dm_ioctl)
-
-#define DM_DEV_CREATE_V1    _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD_V1, struct dm_ioctl)
-#define DM_DEV_REMOVE_V1    _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD_V1, struct dm_ioctl)
-#define DM_DEV_RELOAD_V1    _IOWR(DM_IOCTL, DM_DEV_RELOAD_CMD_V1, struct dm_ioctl)
-#define DM_DEV_SUSPEND_V1   _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD_V1, struct dm_ioctl)
-#define DM_DEV_RENAME_V1    _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD_V1, struct dm_ioctl)
-#define DM_DEV_DEPS_V1      _IOWR(DM_IOCTL, DM_DEV_DEPS_CMD_V1, struct dm_ioctl)
-#define DM_DEV_STATUS_V1    _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD_V1, struct dm_ioctl)
-
-#define DM_TARGET_STATUS_V1 _IOWR(DM_IOCTL, DM_TARGET_STATUS_CMD_V1, struct dm_ioctl)
-#define DM_TARGET_WAIT_V1   _IOWR(DM_IOCTL, DM_TARGET_WAIT_CMD_V1, struct dm_ioctl)
-
-/* *INDENT-OFF* */
-static struct cmd_data _cmd_data_v1[] = {
-       { "create",     DM_DEV_CREATE_V1,       {1, 0, 0} },
-       { "reload",     DM_DEV_RELOAD_V1,       {1, 0, 0} },
-       { "remove",     DM_DEV_REMOVE_V1,       {1, 0, 0} },
-       { "remove_all", DM_REMOVE_ALL_V1,       {1, 0, 0} },
-       { "suspend",    DM_DEV_SUSPEND_V1,      {1, 0, 0} },
-       { "resume",     DM_DEV_SUSPEND_V1,      {1, 0, 0} },
-       { "info",       DM_DEV_STATUS_V1,       {1, 0, 0} },
-       { "deps",       DM_DEV_DEPS_V1,         {1, 0, 0} },
-       { "rename",     DM_DEV_RENAME_V1,       {1, 0, 0} },
-       { "version",    DM_VERSION_V1,          {1, 0, 0} },
-       { "status",     DM_TARGET_STATUS_V1,    {1, 0, 0} },
-       { "table",      DM_TARGET_STATUS_V1,    {1, 0, 0} },
-       { "waitevent",  DM_TARGET_WAIT_V1,      {1, 0, 0} },
-       { "names",      0,                      {4, 0, 0} },
-       { "clear",      0,                      {4, 0, 0} },
-       { "mknodes",    0,                      {4, 0, 0} },
-       { "versions",   0,                      {4, 1, 0} },
-       { "message",    0,                      {4, 2, 0} },
-       { "setgeometry",0,                      {4, 6, 0} },
-};
-/* *INDENT-ON* */
-
-#endif
index 4a8dfc64fb41a4a415b810b6730438bacb56825a..9e78e1cc69f107bfd7712a0cb4b5efa51ef03325 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of the device-mapper userspace tools.
  *
 #include "libdm-targets.h"
 #include "libdm-common.h"
 
-#ifdef DM_COMPAT
-#  include "libdm-compat.h"
-#endif
-
 #include <fcntl.h>
 #include <dirent.h>
 #include <sys/ioctl.h>
@@ -44,8 +40,7 @@
  * in the _cmd_data arrays.
  */
 
-#if !((DM_VERSION_MAJOR == 1 && DM_VERSION_MINOR >= 0) || \
-      (DM_VERSION_MAJOR == 4 && DM_VERSION_MINOR >= 0))
+#if !((DM_VERSION_MAJOR == 4 && DM_VERSION_MINOR >= 6))
 #error The version of dm-ioctl.h included is incompatible.
 #endif
 
@@ -73,9 +68,9 @@ static unsigned _dm_version_minor = 0;
 static unsigned _dm_version_patchlevel = 0;
 static int _log_suppress = 0;
 
-static int _kernel_major;
-static int _kernel_minor;
-static int _kernel_release;
+static int _kernel_major = 0;
+static int _kernel_minor = 0;
+static int _kernel_release = 0;
 
 /*
  * If the kernel dm driver only supports one major number
@@ -92,16 +87,7 @@ static int _version_checked = 0;
 static int _version_ok = 1;
 static unsigned _ioctl_buffer_double_factor = 0;
 
-/*
- * Support both old and new major numbers to ease the transition.
- * Clumsy, but only temporary.
- */
-#if DM_VERSION_MAJOR == 4 && defined(DM_COMPAT)
-const int _dm_compat = 1;
-#else
 const int _dm_compat = 0;
-#endif
-
 
 /* *INDENT-OFF* */
 static struct cmd_data _cmd_data_v4[] = {
@@ -133,7 +119,6 @@ static struct cmd_data _cmd_data_v4[] = {
 };
 /* *INDENT-ON* */
 
-#define ALIGNMENT_V1 sizeof(int)
 #define ALIGNMENT 8
 
 /* FIXME Rejig library to record & use errno instead */
@@ -141,17 +126,18 @@ static struct cmd_data _cmd_data_v4[] = {
 #  define DM_EXISTS_FLAG 0x00000004
 #endif
 
-static void *_align(void *ptr, unsigned int a)
+static char *_align(char *ptr, unsigned int a)
 {
        register unsigned long agn = --a;
 
-       return (void *) (((unsigned long) ptr + agn) & ~agn);
+       return (char *) (((unsigned long) ptr + agn) & ~agn);
 }
 
 static int _uname(void)
 {
        static int _uts_set = 0;
        struct utsname _uts;
+       int parts;
 
        if (_uts_set)
                return 1;
@@ -160,10 +146,14 @@ static int _uname(void)
                log_error("uname failed: %s", strerror(errno));
                return 0;
        }
-       if (sscanf(_uts.release, "%d.%d.%d",
+
+       parts = sscanf(_uts.release, "%d.%d.%d",
                        &_kernel_major,
                        &_kernel_minor,
-                       &_kernel_release) != 3) {
+                       &_kernel_release);
+
+       /* Kernels with a major number of 2 always had 3 parts. */
+       if (parts < 1 || (_kernel_major < 3 && parts < 3)) {
                log_error("Could not determine kernel version used.");
                return 0;
        }
@@ -182,7 +172,8 @@ static int _get_proc_number(const char *file, const char *name,
 {
        FILE *fl;
        char nm[256];
-       int c;
+       char *line = NULL;
+       size_t len;
        uint32_t num;
 
        if (!(fl = fopen(file, "r"))) {
@@ -190,23 +181,23 @@ static int _get_proc_number(const char *file, const char *name,
                return 0;
        }
 
-       while (!feof(fl)) {
-               if (fscanf(fl, "%d %255s\n", &num, &nm[0]) == 2) {
+       while (getline(&line, &len, fl) != -1) {
+               if (sscanf(line, "%d %255s\n", &num, &nm[0]) == 2) {
                        if (!strcmp(name, nm)) {
                                if (number) {
                                        *number = num;
                                        if (fclose(fl))
                                                log_sys_error("fclose", file);
+                                       free(line);
                                        return 1;
                                }
                                dm_bit_set(_dm_bitset, num);
                        }
-               } else do {
-                       c = fgetc(fl);
-               } while (c != EOF && c != '\n');
+               }
        }
        if (fclose(fl))
                log_sys_error("fclose", file);
+       free(line);
 
        if (number) {
                log_error("%s: No entry for %s found", file, name);
@@ -228,7 +219,7 @@ static int _control_device_number(uint32_t *major, uint32_t *minor)
 }
 
 /*
- * Returns 1 if exists; 0 if it doesn't; -1 if it's wrong
+ * Returns 1 if it exists on returning; 0 if it doesn't; -1 if it's wrong.
  */
 static int _control_exists(const char *control, uint32_t major, uint32_t minor)
 {
@@ -248,7 +239,7 @@ static int _control_exists(const char *control, uint32_t major, uint32_t minor)
                return -1;
        }
 
-       if (major && buf.st_rdev != MKDEV(major, minor)) {
+       if (major && buf.st_rdev != MKDEV((dev_t)major, minor)) {
                log_verbose("%s: Wrong device number: (%u, %u) instead of "
                            "(%u, %u)", control,
                            MAJOR(buf.st_mode), MINOR(buf.st_mode),
@@ -267,8 +258,15 @@ static int _create_control(const char *control, uint32_t major, uint32_t minor)
        int ret;
        mode_t old_umask;
 
-       if (!major)
-               return 0;
+       /*
+        * Return if the control already exists with intended major/minor
+        * or there's an error unlinking an apparently incorrect one.
+        */
+       ret = _control_exists(control, major, minor);
+       if (ret == -1)
+               return 0;       /* Failed to unlink existing incorrect node */
+       if (ret)
+               return 1;       /* Already exists and correct */
 
        (void) dm_prepare_selinux_context(dm_dir(), S_IFDIR);
        old_umask = umask(DM_DEV_DIR_UMASK);
@@ -282,12 +280,14 @@ static int _create_control(const char *control, uint32_t major, uint32_t minor)
        log_verbose("Creating device %s (%u, %u)", control, major, minor);
 
        (void) dm_prepare_selinux_context(control, S_IFCHR);
+       old_umask = umask(DM_CONTROL_NODE_UMASK);
        if (mknod(control, S_IFCHR | S_IRUSR | S_IWUSR,
-                 MKDEV(major, minor)) < 0)  {
+                 MKDEV((dev_t)major, minor)) < 0)  {
                log_sys_error("mknod", control);
                (void) dm_prepare_selinux_context(NULL, 0);
                return 0;
        }
+       umask(old_umask);
        (void) dm_prepare_selinux_context(NULL, 0);
 
        return 1;
@@ -357,14 +357,10 @@ static void _close_control_fd(void)
        }
 }
 
-static int _open_and_assign_control_fd(const char *control,
-                                      int ignore_nodev)
+static int _open_and_assign_control_fd(const char *control)
 {
-       _close_control_fd();
-
        if ((_control_fd = open(control, O_RDWR)) < 0) {
-               if (!(ignore_nodev && errno == ENODEV))
-                       log_sys_error("open", control);
+               log_sys_error("open", control);
                return 0;
        }
 
@@ -375,8 +371,8 @@ static int _open_control(void)
 {
 #ifdef DM_IOCTLS
        char control[PATH_MAX];
-       uint32_t major = 0, minor;
-       int dm_mod_autoload_support, needs_open;
+       uint32_t major = MISC_MAJOR;
+       uint32_t minor = MAPPER_CTRL_MINOR;
 
        if (_control_fd != -1)
                return 1;
@@ -387,61 +383,27 @@ static int _open_control(void)
        snprintf(control, sizeof(control), "%s/%s", dm_dir(), DM_CONTROL_NODE);
 
        /*
-        * dm-mod autoloading is supported since kernel 2.6.36.
-        * Udev daemon will try to read modules.devname file extracted
-        * by depmod and create any static nodes needed.
-        * The /dev/mapper/control node can be created and prepared this way.
-        * First access to such node should load dm-mod module automatically.
+        * Prior to 2.6.36 the minor number should be looked up in /proc.
         */
-       dm_mod_autoload_support = KERNEL_VERSION(_kernel_major, _kernel_minor,
-                                 _kernel_release) >= KERNEL_VERSION(2, 6, 36);
+       if ((KERNEL_VERSION(_kernel_major, _kernel_minor, _kernel_release) <
+            KERNEL_VERSION(2, 6, 36)) &&
+           !_control_device_number(&major, &minor))
+               goto_bad;
 
        /*
-        *  If dm-mod autoloading is supported and the control node exists
-        *  already try to open it now. This should autoload dm-mod module.
+        * Create the node with correct major and minor if not already done.
+        * Udev may already have created /dev/mapper/control
+        * from the modules.devname file generated by depmod.
         */
-       if (dm_mod_autoload_support) {
-               if (!_get_proc_number(PROC_DEVICES, MISC_NAME, &major))
-                       /* If major not found, just fallback to hardcoded value. */
-                       major = MISC_MAJOR;
-
-               /* Recreate the node with correct major and minor if needed. */
-               if (!_control_exists(control, major, MAPPER_CTRL_MINOR) &&
-                   !_create_control(control, major, MAPPER_CTRL_MINOR))
-                       goto error;
-
-               _open_and_assign_control_fd(control, 1);
-       }
+       if (!_create_control(control, major, minor))
+               goto_bad;
 
        /*
-        * Get major and minor number assigned for the control node.
-        * In case we make use of the module autoload support, this
-        * information should be accessible now as well.
+        * As of 2.6.36 kernels, the open can trigger autoloading dm-mod.
         */
-       if (!_control_device_number(&major, &minor))
-               log_error("Is device-mapper driver missing from kernel?");
-
-       /*
-        * Check the control node and its major and minor number.
-        * If there's anything wrong, remove the old node and create
-        * a correct one.
-        */
-       if ((needs_open = !_control_exists(control, major, minor)) &&
-           !_create_control(control, major, minor)) {
-               _close_control_fd();
-               goto error;
-       }
-
-       /*
-        * For older kernels without dm-mod autoloading support, we always
-        * need to open the control node here - we still haven't done that!
-        * For newer kernels with dm-mod autoloading, we open it only if the
-        * node was recreated and corrected in previous step.
-        */
-       if ((!dm_mod_autoload_support || needs_open) &&
-            !_open_and_assign_control_fd(control, 0))
-               goto error;
-
+       if (!_open_and_assign_control_fd(control))
+               goto_bad;
+       
        if (!_create_dm_bitset()) {
                log_error("Failed to set up list of device-mapper major numbers");
                return 0;
@@ -449,8 +411,10 @@ static int _open_control(void)
 
        return 1;
 
-error:
+bad:
        log_error("Failure to communicate with kernel device-mapper driver.");
+       if (!geteuid())
+               log_error("Check that device-mapper is available in the kernel.");
        return 0;
 #else
        return 1;
@@ -467,442 +431,33 @@ static void _dm_zfree_string(char *string)
 
 static void _dm_zfree_dmi(struct dm_ioctl *dmi)
 {
-       if (dmi) {
-               memset(dmi, 0, dmi->data_size);
-               dm_free(dmi);
-       }
-}
-
-void dm_task_destroy(struct dm_task *dmt)
-{
-       struct target *t, *n;
-
-       for (t = dmt->head; t; t = n) {
-               n = t->next;
-               _dm_zfree_string(t->params);
-               dm_free(t->type);
-               dm_free(t);
-       }
-
-       if (dmt->dev_name)
-               dm_free(dmt->dev_name);
-
-       if (dmt->newname)
-               dm_free(dmt->newname);
-
-       if (dmt->message)
-               dm_free(dmt->message);
-
-       _dm_zfree_dmi(dmt->dmi.v4);
-
-       if (dmt->uuid)
-               dm_free(dmt->uuid);
-
-       dm_free(dmt);
-}
-
-/*
- * Protocol Version 1 compatibility functions.
- */
-
-#ifdef DM_COMPAT
-
-static void _dm_zfree_dmi_v1(struct dm_ioctl_v1 *dmi)
-{
-       if (dmi) {
-               memset(dmi, 0, dmi->data_size);
-               dm_free(dmi);
-       }
-}
-
-static int _dm_task_get_driver_version_v1(struct dm_task *dmt, char *version,
-                                         size_t size)
-{
-       unsigned int *v;
-
-       if (!dmt->dmi.v1) {
-               version[0] = '\0';
-               return 0;
-       }
-
-       v = dmt->dmi.v1->version;
-       snprintf(version, size, "%u.%u.%u", v[0], v[1], v[2]);
-       return 1;
-}
-
-/* Unmarshall the target info returned from a status call */
-static int _unmarshal_status_v1(struct dm_task *dmt, struct dm_ioctl_v1 *dmi)
-{
-       char *outbuf = (char *) dmi + dmi->data_start;
-       char *outptr = outbuf;
-       int32_t i;
-       struct dm_target_spec_v1 *spec;
-
-       for (i = 0; i < dmi->target_count; i++) {
-               spec = (struct dm_target_spec_v1 *) outptr;
-
-               if (!dm_task_add_target(dmt, spec->sector_start,
-                                       (uint64_t) spec->length,
-                                       spec->target_type,
-                                       outptr + sizeof(*spec))) {
-                       return 0;
-               }
-
-               outptr = outbuf + spec->next;
-       }
-
-       return 1;
-}
-
-static int _dm_format_dev_v1(char *buf, int bufsize, uint32_t dev_major,
-                            uint32_t dev_minor)
-{
-       int r;
-
-       if (bufsize < 8)
-               return 0;
-
-       r = snprintf(buf, bufsize, "%03x:%03x", dev_major, dev_minor);
-       if (r < 0 || r > bufsize - 1)
-               return 0;
-
-       return 1;
-}
-
-static int _dm_task_get_info_v1(struct dm_task *dmt, struct dm_info *info)
-{
-       if (!dmt->dmi.v1)
-               return 0;
-
-       memset(info, 0, sizeof(*info));
-
-       info->exists = dmt->dmi.v1->flags & DM_EXISTS_FLAG ? 1 : 0;
-       if (!info->exists)
-               return 1;
-
-       info->suspended = dmt->dmi.v1->flags & DM_SUSPEND_FLAG ? 1 : 0;
-       info->read_only = dmt->dmi.v1->flags & DM_READONLY_FLAG ? 1 : 0;
-       info->target_count = dmt->dmi.v1->target_count;
-       info->open_count = dmt->dmi.v1->open_count;
-       info->event_nr = 0;
-       info->major = MAJOR(dmt->dmi.v1->dev);
-       info->minor = MINOR(dmt->dmi.v1->dev);
-       info->live_table = 1;
-       info->inactive_table = 0;
-
-       return 1;
-}
-
-static const char *_dm_task_get_name_v1(const struct dm_task *dmt)
-{
-       return (dmt->dmi.v1->name);
-}
-
-static const char *_dm_task_get_uuid_v1(const struct dm_task *dmt)
-{
-       return (dmt->dmi.v1->uuid);
-}
-
-static struct dm_deps *_dm_task_get_deps_v1(struct dm_task *dmt)
-{
-       log_error("deps version 1 no longer supported by libdevmapper");
-       return NULL;
-}
-
-static struct dm_names *_dm_task_get_names_v1(struct dm_task *dmt)
-{
-       return (struct dm_names *) (((void *) dmt->dmi.v1) +
-                                   dmt->dmi.v1->data_start);
-}
-
-static void *_add_target_v1(struct target *t, void *out, void *end)
-{
-       void *out_sp = out;
-       struct dm_target_spec_v1 sp;
-       size_t sp_size = sizeof(struct dm_target_spec_v1);
-       int len;
-
-       out += sp_size;
-       if (out >= end)
-               return_NULL;
-
-       sp.status = 0;
-       sp.sector_start = t->start;
-       sp.length = t->length;
-       strncpy(sp.target_type, t->type, sizeof(sp.target_type));
-
-       len = strlen(t->params);
-
-       if ((out + len + 1) >= end)
-               return_NULL;
-
-       strcpy((char *) out, t->params);
-       out += len + 1;
-
-       /* align next block */
-       out = _align(out, ALIGNMENT_V1);
-
-       sp.next = out - out_sp;
-
-       memcpy(out_sp, &sp, sp_size);
-
-       return out;
-}
-
-static struct dm_ioctl_v1 *_flatten_v1(struct dm_task *dmt)
-{
-       const size_t min_size = 16 * 1024;
-       const int (*version)[3];
-
-       struct dm_ioctl_v1 *dmi;
-       struct target *t;
-       size_t len = sizeof(struct dm_ioctl_v1);
-       void *b, *e;
-       int count = 0;
-
-       for (t = dmt->head; t; t = t->next) {
-               len += sizeof(struct dm_target_spec_v1);
-               len += strlen(t->params) + 1 + ALIGNMENT_V1;
-               count++;
-       }
-
-       if (count && dmt->newname) {
-               log_error("targets and newname are incompatible");
-               return NULL;
-       }
-
-       if (dmt->newname)
-               len += strlen(dmt->newname) + 1;
-
-       /*
-        * Give len a minimum size so that we have space to store
-        * dependencies or status information.
-        */
-       if (len < min_size)
-               len = min_size;
-
-       if (!(dmi = dm_malloc(len)))
-               return NULL;
-
-       memset(dmi, 0, len);
-
-       version = &_cmd_data_v1[dmt->type].version;
-
-       dmi->version[0] = (*version)[0];
-       dmi->version[1] = (*version)[1];
-       dmi->version[2] = (*version)[2];
-
-       dmi->data_size = len;
-       dmi->data_start = sizeof(struct dm_ioctl_v1);
-
-       if (dmt->dev_name)
-               strncpy(dmi->name, dmt->dev_name, sizeof(dmi->name));
-
-       if (dmt->type == DM_DEVICE_SUSPEND)
-               dmi->flags |= DM_SUSPEND_FLAG;
-       if (dmt->read_only)
-               dmi->flags |= DM_READONLY_FLAG;
-
-       if (dmt->minor >= 0) {
-               if (dmt->major <= 0) {
-                       log_error("Missing major number for persistent device");
-                       return NULL;
-               }
-               dmi->flags |= DM_PERSISTENT_DEV_FLAG;
-               dmi->dev = MKDEV(dmt->major, dmt->minor);
-       }
-
-       if (dmt->uuid)
-               strncpy(dmi->uuid, dmt->uuid, sizeof(dmi->uuid));
-
-       dmi->target_count = count;
-
-       b = (void *) (dmi + 1);
-       e = (void *) ((char *) dmi + len);
-
-       for (t = dmt->head; t; t = t->next)
-               if (!(b = _add_target_v1(t, b, e))) {
-                       log_error("Ran out of memory building ioctl parameter");
-                       goto bad;
-               }
-
-       if (dmt->newname)
-               strcpy(b, dmt->newname);
-
-       return dmi;
-
-      bad:
-       _dm_zfree_dmi_v1(dmi);
-       return NULL;
-}
-
-static int _dm_names_v1(struct dm_ioctl_v1 *dmi)
-{
-       const char *dev_dir = dm_dir();
-       int r = 1, len;
-       const char *name;
-       struct dirent *dirent;
-       DIR *d;
-       struct dm_names *names, *old_names = NULL;
-       void *end = (void *) dmi + dmi->data_size;
-       struct stat buf;
-       char path[PATH_MAX];
-
-       log_warn("WARNING: Device list may be incomplete with interface "
-                 "version 1.");
-       log_warn("Please upgrade your kernel device-mapper driver.");
-
-       if (!(d = opendir(dev_dir))) {
-               log_sys_error("opendir", dev_dir);
-               return 0;
-       }
-
-       names = (struct dm_names *) ((void *) dmi + dmi->data_start);
-
-       names->dev = 0;         /* Flags no data */
-
-       while ((dirent = readdir(d))) {
-               name = dirent->d_name;
-
-               if (name[0] == '.' || !strcmp(name, "control"))
-                       continue;
-
-               if (old_names)
-                       old_names->next = (uint32_t) ((void *) names -
-                                                     (void *) old_names);
-               snprintf(path, sizeof(path), "%s/%s", dev_dir, name);
-               if (stat(path, &buf)) {
-                       log_sys_error("stat", path);
-                       continue;
-               }
-               if (!S_ISBLK(buf.st_mode))
-                       continue;
-               names->dev = (uint64_t) buf.st_rdev;
-               names->next = 0;
-               len = strlen(name);
-               if (((void *) (names + 1) + len + 1) >= end) {
-                       log_error("Insufficient buffer space for device list");
-                       r = 0;
-                       break;
-               }
-
-               strcpy(names->name, name);
-
-               old_names = names;
-               names = _align((void *) ++names + len + 1, ALIGNMENT);
-       }
-
-       if (closedir(d))
-               log_sys_error("closedir", dev_dir);
-
-       return r;
-}
-
-static int _dm_task_run_v1(struct dm_task *dmt)
-{
-       struct dm_ioctl_v1 *dmi;
-       unsigned int command;
-
-       dmi = _flatten_v1(dmt);
-       if (!dmi) {
-               log_error("Couldn't create ioctl argument.");
-               return 0;
-       }
-
-       if (!_open_control())
-               return 0;
-
-       if ((unsigned) dmt->type >=
-           (sizeof(_cmd_data_v1) / sizeof(*_cmd_data_v1))) {
-               log_error(INTERNAL_ERROR "unknown device-mapper task %d",
-                         dmt->type);
-               goto bad;
-       }
-
-       command = _cmd_data_v1[dmt->type].cmd;
-
-       if (dmt->type == DM_DEVICE_TABLE)
-               dmi->flags |= DM_STATUS_TABLE_FLAG;
-
-       if (dmt->new_uuid) {
-               log_error("Changing UUID is not supported by kernel.");
-               goto bad;
-       }
-
-       log_debug("dm %s %s %s%s%s [%u]", _cmd_data_v1[dmt->type].name,
-                 dmi->name, dmi->uuid, dmt->newname ? " " : "",
-                 dmt->newname ? dmt->newname : "",
-                 dmi->data_size);
-       if (dmt->type == DM_DEVICE_LIST) {
-               if (!_dm_names_v1(dmi))
-                       goto bad;
-       } 
-#ifdef DM_IOCTLS
-       else if (ioctl(_control_fd, command, dmi) < 0) {
-               if (_log_suppress)
-                       log_verbose("device-mapper: %s ioctl failed: %s", 
-                                   _cmd_data_v1[dmt->type].name,
-                                   strerror(errno));
-               else
-                       log_error("device-mapper: %s ioctl failed: %s",
-                                 _cmd_data_v1[dmt->type].name,
-                                 strerror(errno));
-               goto bad;
-       }
-#else /* Userspace alternative for testing */
-#endif
-
-       if (dmi->flags & DM_BUFFER_FULL_FLAG)
-               /* FIXME Increase buffer size and retry operation (if query) */
-               log_error("WARNING: libdevmapper buffer too small for data");
-
-       switch (dmt->type) {
-       case DM_DEVICE_CREATE:
-               add_dev_node(dmt->dev_name, MAJOR(dmi->dev), MINOR(dmi->dev),
-                            dmt->uid, dmt->gid, dmt->mode, 0);
-               break;
-
-       case DM_DEVICE_REMOVE:
-               rm_dev_node(dmt->dev_name, 0);
-               break;
-
-       case DM_DEVICE_RENAME:
-               rename_dev_node(dmt->dev_name, dmt->newname, 0);
-               break;
-
-       case DM_DEVICE_MKNODES:
-               if (dmi->flags & DM_EXISTS_FLAG)
-                       add_dev_node(dmt->dev_name, MAJOR(dmi->dev),
-                                    MINOR(dmi->dev), dmt->uid,
-                                    dmt->gid, dmt->mode, 0);
-               else
-                       rm_dev_node(dmt->dev_name, 0);
-               break;
-
-       case DM_DEVICE_STATUS:
-       case DM_DEVICE_TABLE:
-               if (!_unmarshal_status_v1(dmt, dmi))
-                       goto bad;
-               break;
-
-       case DM_DEVICE_SUSPEND:
-       case DM_DEVICE_RESUME:
-               dmt->type = DM_DEVICE_INFO;
-               if (!dm_task_run(dmt))
-                       goto bad;
-               _dm_zfree_dmi_v1(dmi);  /* We'll use what info returned */
-               return 1;
+       if (dmi) {
+               memset(dmi, 0, dmi->data_size);
+               dm_free(dmi);
        }
+}
 
-       dmt->dmi.v1 = dmi;
-       return 1;
+void dm_task_destroy(struct dm_task *dmt)
+{
+       struct target *t, *n;
 
-      bad:
-       _dm_zfree_dmi_v1(dmi);
-       return 0;
-}
+       for (t = dmt->head; t; t = n) {
+               n = t->next;
+               _dm_zfree_string(t->params);
+               dm_free(t->type);
+               dm_free(t);
+       }
 
-#endif
+       _dm_zfree_dmi(dmt->dmi.v4);
+       dm_free(dmt->dev_name);
+       dm_free(dmt->mangled_dev_name);
+       dm_free(dmt->newname);
+       dm_free(dmt->message);
+       dm_free(dmt->geometry);
+       dm_free(dmt->uuid);
+       dm_free(dmt->mangled_uuid);
+       dm_free(dmt);
+}
 
 /*
  * Protocol Version 4 functions.
@@ -912,20 +467,22 @@ int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size)
 {
        unsigned *v;
 
-#ifdef DM_COMPAT
-       if (_dm_version == 1)
-               return _dm_task_get_driver_version_v1(dmt, version, size);
-#endif
-
        if (!dmt->dmi.v4) {
-               version[0] = '\0';
+               if (version)
+                       version[0] = '\0';
                return 0;
        }
 
        v = dmt->dmi.v4->version;
-       snprintf(version, size, "%u.%u.%u", v[0], v[1], v[2]);
        _dm_version_minor = v[1];
        _dm_version_patchlevel = v[2];
+       if (version &&
+           (snprintf(version, size, "%u.%u.%u", v[0], v[1], v[2]) < 0)) {
+               log_error("Buffer for version is to short.");
+               if (size > 0)
+                       version[0] = '\0';
+               return 0;
+       }
 
        return 1;
 }
@@ -945,7 +502,8 @@ static int _check_version(char *version, size_t size, int log_suppress)
                _log_suppress = 1;
 
        r = dm_task_run(task);
-       dm_task_get_driver_version(task, version, size);
+       if (!dm_task_get_driver_version(task, version, size))
+               stack;
        dm_task_destroy(task);
        _log_suppress = 0;
 
@@ -970,7 +528,7 @@ int dm_check_version(void)
                return 1;
 
        if (!_dm_compat)
-               goto bad;
+               goto_bad;
 
        log_verbose("device-mapper ioctl protocol version %u failed. "
                    "Trying protocol version 1.", _dm_version);
@@ -995,8 +553,25 @@ int dm_check_version(void)
 int dm_cookie_supported(void)
 {
        return (dm_check_version() &&
-               _dm_version >= 4 &&
-               _dm_version_minor >= 15);
+               _dm_version >= 4 &&
+               _dm_version_minor >= 15);
+}
+
+static int dm_inactive_supported(void)
+{
+       int inactive_supported = 0;
+
+       if (dm_check_version() && _dm_version >= 4) {
+               if (_dm_version_minor >= 16)
+                       inactive_supported = 1; /* upstream */
+               else if (_dm_version_minor == 11 &&
+                        (_dm_version_patchlevel >= 6 &&
+                         _dm_version_patchlevel <= 40)) {
+                       inactive_supported = 1; /* RHEL 5.7 */
+               }
+       }
+
+       return inactive_supported;
 }
 
 void *dm_get_next_target(struct dm_task *dmt, void *next,
@@ -1008,8 +583,13 @@ void *dm_get_next_target(struct dm_task *dmt, void *next,
        if (!t)
                t = dmt->head;
 
-       if (!t)
+       if (!t) {
+               *start = 0;
+               *length = 0;
+               *target_type = 0;
+               *params = 0;
                return NULL;
+       }
 
        *start = t->start;
        *length = t->length;
@@ -1047,11 +627,6 @@ int dm_format_dev(char *buf, int bufsize, uint32_t dev_major,
 {
        int r;
 
-#ifdef DM_COMPAT
-       if (_dm_version == 1)
-               return _dm_format_dev_v1(buf, bufsize, dev_major, dev_minor);
-#endif
-
        if (bufsize < 8)
                return 0;
 
@@ -1064,11 +639,6 @@ int dm_format_dev(char *buf, int bufsize, uint32_t dev_major,
 
 int dm_task_get_info(struct dm_task *dmt, struct dm_info *info)
 {
-#ifdef DM_COMPAT
-       if (_dm_version == 1)
-               return _dm_task_get_info_v1(dmt, info);
-#endif
-
        if (!dmt->dmi.v4)
                return 0;
 
@@ -1093,70 +663,33 @@ int dm_task_get_info(struct dm_task *dmt, struct dm_info *info)
 }
 
 uint32_t dm_task_get_read_ahead(const struct dm_task *dmt, uint32_t *read_ahead)
-{              
+{
        const char *dev_name;
 
        *read_ahead = 0;
 
-#ifdef DM_COMPAT
-       /* Not supporting this */
-        if (_dm_version == 1)
-                return 1;
-#endif  
-
-        if (!dmt->dmi.v4 || !(dmt->dmi.v4->flags & DM_EXISTS_FLAG))
+       if (!dmt->dmi.v4 || !(dmt->dmi.v4->flags & DM_EXISTS_FLAG))
                return 0;
 
        if (*dmt->dmi.v4->name)
                dev_name = dmt->dmi.v4->name;
-       else if (dmt->dev_name)
-               dev_name = dmt->dev_name;
-       else {
+       else if (!(dev_name = DEV_NAME(dmt))) {
                log_error("Get read ahead request failed: device name unrecorded.");
                return 0;
        }
 
-       return get_dev_node_read_ahead(dev_name, read_ahead);
-}
-
-const char *dm_task_get_name(const struct dm_task *dmt)
-{
-#ifdef DM_COMPAT
-       if (_dm_version == 1)
-               return _dm_task_get_name_v1(dmt);
-#endif
-
-       return (dmt->dmi.v4->name);
-}
-
-const char *dm_task_get_uuid(const struct dm_task *dmt)
-{
-#ifdef DM_COMPAT
-       if (_dm_version == 1)
-               return _dm_task_get_uuid_v1(dmt);
-#endif
-
-       return (dmt->dmi.v4->uuid);
+       return get_dev_node_read_ahead(dev_name, MAJOR(dmt->dmi.v4->dev),
+                                      MINOR(dmt->dmi.v4->dev), read_ahead);
 }
 
 struct dm_deps *dm_task_get_deps(struct dm_task *dmt)
 {
-#ifdef DM_COMPAT
-       if (_dm_version == 1)
-               return _dm_task_get_deps_v1(dmt);
-#endif
-
        return (struct dm_deps *) (((char *) dmt->dmi.v4) +
                                   dmt->dmi.v4->data_start);
 }
 
 struct dm_names *dm_task_get_names(struct dm_task *dmt)
 {
-#ifdef DM_COMPAT
-       if (_dm_version == 1)
-               return _dm_task_get_names_v1(dmt);
-#endif
-
        return (struct dm_names *) (((char *) dmt->dmi.v4) +
                                    dmt->dmi.v4->data_start);
 }
@@ -1188,39 +721,52 @@ int dm_task_suppress_identical_reload(struct dm_task *dmt)
        return 1;
 }
 
-int dm_task_set_newuuid(struct dm_task *dmt, const char *newuuid)
+int dm_task_set_add_node(struct dm_task *dmt, dm_add_node_t add_node)
 {
-       if (strlen(newuuid) >= DM_UUID_LEN) {
-               log_error("Uuid \"%s\" too long", newuuid);
+       switch (add_node) {
+       case DM_ADD_NODE_ON_RESUME:
+       case DM_ADD_NODE_ON_CREATE:
+               dmt->add_node = add_node;
+               return 1;
+       default:
+               log_error("Unknown add node parameter");
                return 0;
        }
+}
 
-       if (!(dmt->newname = dm_strdup(newuuid))) {
-               log_error("dm_task_set_newuuid: strdup(%s) failed", newuuid);
+int dm_task_set_newuuid(struct dm_task *dmt, const char *newuuid)
+{
+       dm_string_mangling_t mangling_mode = dm_get_name_mangling_mode();
+       char mangled_uuid[DM_UUID_LEN];
+       int r = 0;
+
+       if (strlen(newuuid) >= DM_UUID_LEN) {
+               log_error("Uuid \"%s\" too long", newuuid);
                return 0;
        }
-       dmt->new_uuid = 1;
 
-       return 1;
-}
+       if (!check_multiple_mangled_string_allowed(newuuid, "new UUID", mangling_mode))
+               return_0;
 
-int dm_task_set_newname(struct dm_task *dmt, const char *newname)
-{
-       if (strchr(newname, '/')) {
-               log_error("Name \"%s\" invalid. It contains \"/\".", newname);
+       if (mangling_mode != DM_STRING_MANGLING_NONE &&
+           (r = mangle_string(newuuid, "new UUID", strlen(newuuid), mangled_uuid,
+                              sizeof(mangled_uuid), mangling_mode)) < 0) {
+               log_error("Failed to mangle new device UUID \"%s\"", newuuid);
                return 0;
        }
 
-       if (strlen(newname) >= DM_NAME_LEN) {
-               log_error("Name \"%s\" too long", newname);
-               return 0;
+       if (r) {
+               log_debug("New device uuid mangled [%s]: %s --> %s",
+                         mangling_mode == DM_STRING_MANGLING_AUTO ? "auto" : "hex",
+                         newuuid, mangled_uuid);
+               newuuid = mangled_uuid;
        }
 
-       if (!(dmt->newname = dm_strdup(newname))) {
-               log_error("dm_task_set_newname: strdup(%s) failed", newname);
+       if (!(dmt->newname = dm_strdup(newuuid))) {
+               log_error("dm_task_set_newuuid: strdup(%s) failed", newuuid);
                return 0;
        }
-       dmt->new_uuid = 0;
+       dmt->new_uuid = 1;
 
        return 1;
 }
@@ -1242,16 +788,11 @@ int dm_task_set_sector(struct dm_task *dmt, uint64_t sector)
        return 1;
 }
 
-int dm_task_set_geometry(struct dm_task *dmt, const char *cylinders, const char *heads, const char *sectors, const char *start)
+int dm_task_set_geometry(struct dm_task *dmt, const char *cylinders, const char *heads,
+                        const char *sectors, const char *start)
 {
-       size_t len = strlen(cylinders) + 1 + strlen(heads) + 1 + strlen(sectors) + 1 + strlen(start) + 1;
-
-       if (!(dmt->geometry = dm_malloc(len))) {
-               log_error("dm_task_set_geometry: dm_malloc failed");
-               return 0;
-       }
-
-       if (sprintf(dmt->geometry, "%s %s %s %s", cylinders, heads, sectors, start) < 0) {
+       if (dm_asprintf(&(dmt->geometry), "%s %s %s %s",
+                       cylinders, heads, sectors, start) < 0) {
                log_error("dm_task_set_geometry: sprintf failed");
                return 0;
        }
@@ -1280,6 +821,20 @@ int dm_task_skip_lockfs(struct dm_task *dmt)
        return 1;
 }
 
+int dm_task_secure_data(struct dm_task *dmt)
+{
+       dmt->secure_data = 1;
+
+       return 1;
+}
+
+int dm_task_retry_remove(struct dm_task *dmt)
+{
+       dmt->retry_remove = 1;
+
+       return 1;
+}
+
 int dm_task_query_inactive_table(struct dm_task *dmt)
 {
        dmt->query_inactive_table = 1;
@@ -1297,16 +852,19 @@ int dm_task_set_event_nr(struct dm_task *dmt, uint32_t event_nr)
 struct target *create_target(uint64_t start, uint64_t len, const char *type,
                             const char *params)
 {
-       struct target *t = dm_malloc(sizeof(*t));
+       struct target *t;
 
-       if (!t) {
+       if (strlen(type) >= DM_MAX_TYPE_NAME) {
+               log_error("Target type name %s is too long.", type);
+               return NULL;
+       }
+
+       if (!(t = dm_zalloc(sizeof(*t)))) {
                log_error("create_target: malloc(%" PRIsize_t ") failed",
                          sizeof(*t));
                return NULL;
        }
 
-       memset(t, 0, sizeof(*t));
-
        if (!(t->params = dm_strdup(params))) {
                log_error("create_target: strdup(params) failed");
                goto bad;
@@ -1328,29 +886,53 @@ struct target *create_target(uint64_t start, uint64_t len, const char *type,
        return NULL;
 }
 
-static void *_add_target(struct target *t, void *out, void *end)
+static char *_add_target(struct target *t, char *out, char *end)
 {
-       void *out_sp = out;
+       char *out_sp = out;
        struct dm_target_spec sp;
        size_t sp_size = sizeof(struct dm_target_spec);
+       unsigned int backslash_count = 0;
        int len;
+       char *pt;
 
-       out += sp_size;
-       if (out >= end)
-               return_NULL;
+       if (strlen(t->type) >= sizeof(sp.target_type)) {
+               log_error("Target type name %s is too long.", t->type);
+               return NULL;
+       }
 
        sp.status = 0;
        sp.sector_start = t->start;
        sp.length = t->length;
-       strncpy(sp.target_type, t->type, sizeof(sp.target_type));
+       strncpy(sp.target_type, t->type, sizeof(sp.target_type) - 1);
+       sp.target_type[sizeof(sp.target_type) - 1] = '\0';
+
+       out += sp_size;
+       pt = t->params;
 
-       len = strlen(t->params);
+       while (*pt)
+               if (*pt++ == '\\')
+                       backslash_count++;
+       len = strlen(t->params) + backslash_count;
 
-       if ((out + len + 1) >= end)
-               return_NULL;
+       if ((out >= end) || (out + len + 1) >= end) {
+               log_error("Ran out of memory building ioctl parameter");
+               return NULL;
+       }
 
-       strcpy((char *) out, t->params);
-       out += len + 1;
+       if (backslash_count) {
+               /* replace "\" with "\\" */
+               pt = t->params;
+               do {
+                       if (*pt == '\\')
+                               *out++ = '\\';
+                       *out++ = *pt++;
+               } while (*pt);
+               *out++ = '\0';
+       }
+       else {
+               strcpy(out, t->params);
+               out += len + 1;
+       }
 
        /* align next block */
        out = _align(out, ALIGNMENT);
@@ -1381,7 +963,7 @@ static int _lookup_dev_name(uint64_t dev, char *buf, size_t len)
                goto out;
  
        do {
-               names = (void *) names + next;
+               names = (struct dm_names *)((char *) names + next);
                if (names->dev == dev) {
                        strncpy(buf, names->name, len);
                        r = 1;
@@ -1404,7 +986,7 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
        struct target *t;
        struct dm_target_msg *tmsg;
        size_t len = sizeof(struct dm_ioctl);
-       void *b, *e;
+       char *b, *e;
        int count = 0;
 
        for (t = dmt->head; t; t = t->next) {
@@ -1497,11 +1079,11 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
                }
 
                dmi->flags |= DM_PERSISTENT_DEV_FLAG;
-               dmi->dev = MKDEV(dmt->major, dmt->minor);
+               dmi->dev = MKDEV((dev_t)dmt->major, dmt->minor);
        }
 
        /* Does driver support device number referencing? */
-       if (_dm_version_minor < 3 && !dmt->dev_name && !dmt->uuid && dmi->dev) {
+       if (_dm_version_minor < 3 && !DEV_NAME(dmt) && !DEV_UUID(dmt) && dmi->dev) {
                if (!_lookup_dev_name(dmi->dev, dmi->name, sizeof(dmi->name))) {
                        log_error("Unable to find name for device (%" PRIu32
                                  ":%" PRIu32 ")", dmt->major, dmt->minor);
@@ -1513,12 +1095,12 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
        }
 
        /* FIXME Until resume ioctl supplies name, use dev_name for readahead */
-       if (dmt->dev_name && (dmt->type != DM_DEVICE_RESUME || dmt->minor < 0 ||
+       if (DEV_NAME(dmt) && (dmt->type != DM_DEVICE_RESUME || dmt->minor < 0 ||
                              dmt->major < 0))
-               strncpy(dmi->name, dmt->dev_name, sizeof(dmi->name));
+               strncpy(dmi->name, DEV_NAME(dmt), sizeof(dmi->name));
 
-       if (dmt->uuid)
-               strncpy(dmi->uuid, dmt->uuid, sizeof(dmi->uuid));
+       if (DEV_UUID(dmt))
+               strncpy(dmi->uuid, DEV_UUID(dmt), sizeof(dmi->uuid));
 
        if (dmt->type == DM_DEVICE_SUSPEND)
                dmi->flags |= DM_SUSPEND_FLAG;
@@ -1528,8 +1110,14 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
                dmi->flags |= DM_READONLY_FLAG;
        if (dmt->skip_lockfs)
                dmi->flags |= DM_SKIP_LOCKFS_FLAG;
+       if (dmt->secure_data) {
+               if (_dm_version_minor < 20)
+                       log_verbose("Secure data flag unsupported by kernel. "
+                                   "Buffers will not be wiped after use.");
+               dmi->flags |= DM_SECURE_DATA_FLAG;
+       }
        if (dmt->query_inactive_table) {
-               if (_dm_version_minor < 16)
+               if (!dm_inactive_supported())
                        log_warn("WARNING: Inactive table query unsupported "
                                 "by kernel.  It will use live table.");
                dmi->flags |= DM_QUERY_INACTIVE_TABLE_FLAG;
@@ -1546,14 +1134,12 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
        dmi->target_count = count;
        dmi->event_nr = dmt->event_nr;
 
-       b = (void *) (dmi + 1);
-       e = (void *) ((char *) dmi + len);
+       b = (char *) (dmi + 1);
+       e = (char *) dmi + len;
 
        for (t = dmt->head; t; t = t->next)
-               if (!(b = _add_target(t, b, e))) {
-                       log_error("Ran out of memory building ioctl parameter");
-                       goto bad;
-               }
+               if (!(b = _add_target(t, b, e)))
+                       goto_bad;
 
        if (dmt->newname)
                strcpy(b, dmt->newname);
@@ -1633,7 +1219,7 @@ static int _process_all_v4(struct dm_task *dmt)
                goto out;
 
        do {
-               names = (void *) names + next;
+               names = (struct dm_names *)((char *) names + next);
                if (!dm_task_set_name(dmt, names->name)) {
                        r = 0;
                        goto out;
@@ -1691,23 +1277,16 @@ static int _create_and_load_v4(struct dm_task *dmt)
 
        /* Use new task struct to create the device */
        if (!(task = dm_task_create(DM_DEVICE_CREATE))) {
-               log_error("Failed to create device-mapper task struct");
                _udev_complete(dmt);
-               return 0;
+               return_0;
        }
 
        /* Copy across relevant fields */
-       if (dmt->dev_name && !dm_task_set_name(task, dmt->dev_name)) {
-               dm_task_destroy(task);
-               _udev_complete(dmt);
-               return 0;
-       }
+       if (dmt->dev_name && !dm_task_set_name(task, dmt->dev_name))
+               goto_bad;
 
-       if (dmt->uuid && !dm_task_set_uuid(task, dmt->uuid)) {
-               dm_task_destroy(task);
-               _udev_complete(dmt);
-               return 0;
-       }
+       if (dmt->uuid && !dm_task_set_uuid(task, dmt->uuid))
+               goto_bad;
 
        task->major = dmt->major;
        task->minor = dmt->minor;
@@ -1717,40 +1296,41 @@ static int _create_and_load_v4(struct dm_task *dmt)
        /* FIXME: Just for udev_check in dm_task_run. Can we avoid this? */
        task->event_nr = dmt->event_nr & DM_UDEV_FLAGS_MASK;
        task->cookie_set = dmt->cookie_set;
+       task->add_node = dmt->add_node;
+
+       if (!dm_task_run(task))
+               goto_bad;
 
-       r = dm_task_run(task);
        dm_task_destroy(task);
-       if (!r) {
-               _udev_complete(dmt);
-               return 0;
-       }
 
        /* Next load the table */
        if (!(task = dm_task_create(DM_DEVICE_RELOAD))) {
-               log_error("Failed to create device-mapper task struct");
+               stack;
                _udev_complete(dmt);
-               r = 0;
                goto revert;
        }
 
        /* Copy across relevant fields */
        if (dmt->dev_name && !dm_task_set_name(task, dmt->dev_name)) {
+               stack;
                dm_task_destroy(task);
                _udev_complete(dmt);
-               r = 0;
                goto revert;
        }
 
        task->read_only = dmt->read_only;
        task->head = dmt->head;
        task->tail = dmt->tail;
+       task->secure_data = dmt->secure_data;
 
        r = dm_task_run(task);
 
        task->head = NULL;
        task->tail = NULL;
        dm_task_destroy(task);
+
        if (!r) {
+               stack;
                _udev_complete(dmt);
                goto revert;
        }
@@ -1759,16 +1339,18 @@ static int _create_and_load_v4(struct dm_task *dmt)
        dmt->type = DM_DEVICE_RESUME;
        dm_free(dmt->uuid);
        dmt->uuid = NULL;
+       dm_free(dmt->mangled_uuid);
+       dmt->mangled_uuid = NULL;
 
-       r = dm_task_run(dmt);
-
-       if (r)
-               return r;
+       if (dm_task_run(dmt))
+               return 1;
 
       revert:
-       dmt->type = DM_DEVICE_REMOVE;
+       dmt->type = DM_DEVICE_REMOVE;
        dm_free(dmt->uuid);
        dmt->uuid = NULL;
+       dm_free(dmt->mangled_uuid);
+       dmt->mangled_uuid = NULL;
 
        /*
         * Also udev-synchronize "remove" dm task that is a part of this revert!
@@ -1780,13 +1362,19 @@ static int _create_and_load_v4(struct dm_task *dmt)
                if (!dm_task_set_cookie(dmt, &cookie,
                                        (dmt->event_nr & DM_UDEV_FLAGS_MASK) >>
                                        DM_UDEV_FLAGS_SHIFT))
-                        stack; /* keep going */
+                       stack; /* keep going */
        }
 
        if (!dm_task_run(dmt))
                log_error("Failed to revert device creation.");
 
-       return r;
+       return 0;
+
+      bad:
+       dm_task_destroy(task);
+       _udev_complete(dmt);
+
+       return 0;
 }
 
 uint64_t dm_task_get_existing_table_size(struct dm_task *dmt)
@@ -1798,6 +1386,7 @@ static int _reload_with_suppression_v4(struct dm_task *dmt)
 {
        struct dm_task *task;
        struct target *t1, *t2;
+       size_t len;
        int r;
 
        /* New task to get existing table information */
@@ -1833,15 +1422,16 @@ static int _reload_with_suppression_v4(struct dm_task *dmt)
                t2 = t2->next;
        dmt->existing_table_size = t2 ? t2->start + t2->length : 0;
 
-       if ((task->dmi.v4->flags & DM_READONLY_FLAG) ? 1 : 0 != dmt->read_only)
+       if (((task->dmi.v4->flags & DM_READONLY_FLAG) ? 1 : 0) != dmt->read_only)
                goto no_match;
 
        t1 = dmt->head;
        t2 = task->head;
 
        while (t1 && t2) {
-               while (t2->params[strlen(t2->params) - 1] == ' ')
-                       t2->params[strlen(t2->params) - 1] = '\0';
+               len = strlen(t2->params);
+               while (len-- > 0 && t2->params[len] == ' ')
+                       t2->params[len] = '\0';
                if ((t1->start != t2->start) ||
                    (t1->length != t2->length) ||
                    (strcmp(t1->type, t2->type)) ||
@@ -1868,6 +1458,107 @@ no_match:
        return r;
 }
 
+static int _check_children_not_suspended_v4(struct dm_task *dmt, uint64_t device)
+{
+       struct dm_task *task;
+       struct dm_info info;
+       struct dm_deps *deps;
+       int r = 0;
+       uint32_t i;
+
+       /* Find dependencies */
+       if (!(task = dm_task_create(DM_DEVICE_DEPS)))
+               return 0;
+
+       /* Copy across or set relevant fields */
+       if (device) {
+               task->major = MAJOR(device);
+               task->minor = MINOR(device);
+       } else {
+               if (dmt->dev_name && !dm_task_set_name(task, dmt->dev_name))
+                       goto out;
+
+               if (dmt->uuid && !dm_task_set_uuid(task, dmt->uuid))
+                       goto out;
+
+               task->major = dmt->major;
+               task->minor = dmt->minor;
+       }
+
+       task->uid = dmt->uid;
+       task->gid = dmt->gid;
+       task->mode = dmt->mode;
+       /* FIXME: Just for udev_check in dm_task_run. Can we avoid this? */
+       task->event_nr = dmt->event_nr & DM_UDEV_FLAGS_MASK;
+       task->cookie_set = dmt->cookie_set;
+       task->add_node = dmt->add_node;
+       
+       if (!(r = dm_task_run(task)))
+               goto out;
+
+       if (!dm_task_get_info(task, &info) || !info.exists)
+               goto out;
+
+       /*
+        * Warn if any of the devices this device depends upon are already
+        * suspended: I/O could become trapped between the two devices.
+        */
+       if (info.suspended) {
+               if (!device)
+                       log_debug("Attempting to suspend a device that is already suspended "
+                                 "(%u:%u)", info.major, info.minor);
+               else
+                       log_error(INTERNAL_ERROR "Attempt to suspend device %s%s%s%.0d%s%.0d%s%s"
+                                 "that uses already-suspended device (%u:%u)", 
+                                 DEV_NAME(dmt) ? : "", DEV_UUID(dmt) ? : "",
+                                 dmt->major > 0 ? "(" : "",
+                                 dmt->major > 0 ? dmt->major : 0,
+                                 dmt->major > 0 ? ":" : "",
+                                 dmt->minor > 0 ? dmt->minor : 0,
+                                 dmt->major > 0 && dmt->minor == 0 ? "0" : "",
+                                 dmt->major > 0 ? ") " : "",
+                                 info.major, info.minor);
+
+               /* No need for further recursion */
+               r = 1;
+               goto out;
+       }
+
+       if (!(deps = dm_task_get_deps(task)))
+               goto out;
+
+       for (i = 0; i < deps->count; i++) {
+               /* Only recurse with dm devices */
+               if (MAJOR(deps->device[i]) != _dm_device_major)
+                       continue;
+
+               if (!_check_children_not_suspended_v4(task, deps->device[i]))
+                       goto out;
+       }
+
+       r = 1;
+
+out:
+       dm_task_destroy(task);
+
+       return r;
+}
+
+static int _suspend_with_validation_v4(struct dm_task *dmt)
+{
+       /* Avoid recursion */
+       dmt->enable_checks = 0;
+
+       /*
+        * Ensure we can't leave any I/O trapped between suspended devices.
+        */
+       if (!_check_children_not_suspended_v4(dmt, 0))
+               return 0;
+
+       /* Finally, perform the original suspend. */
+       return dm_task_run(dmt);
+}
+
 static const char *_sanitise_message(char *message)
 {
        const char *sanitised_message = message ?: "";
@@ -1880,13 +1571,76 @@ static const char *_sanitise_message(char *message)
        return sanitised_message;
 }
 
+static int _do_dm_ioctl_unmangle_string(char *str, const char *str_name,
+                                       char *buf, size_t buf_size,
+                                       dm_string_mangling_t mode)
+{
+       int r;
+
+       if (mode == DM_STRING_MANGLING_NONE)
+               return 1;
+
+       if (!check_multiple_mangled_string_allowed(str, str_name, mode))
+               return_0;
+
+       if ((r = unmangle_string(str, str_name, strlen(str), buf, buf_size, mode)) < 0) {
+               log_debug("_do_dm_ioctl_unmangle_string: failed to "
+                         "unmangle %s \"%s\"", str_name, str);
+               return 0;
+       } else if (r)
+               memcpy(str, buf, strlen(buf) + 1);
+
+       return 1;
+}
+
+static int _dm_ioctl_unmangle_names(int type, struct dm_ioctl *dmi)
+{
+       char buf[DM_NAME_LEN];
+       struct dm_names *names;
+       unsigned next = 0;
+       char *name;
+       int r = 1;
+
+       if ((name = dmi->name))
+               r = _do_dm_ioctl_unmangle_string(name, "name", buf, sizeof(buf),
+                                                dm_get_name_mangling_mode());
+
+       if (type == DM_DEVICE_LIST &&
+           ((names = ((struct dm_names *) ((char *)dmi + dmi->data_start)))) &&
+           names->dev) {
+               do {
+                       names = (struct dm_names *)((char *) names + next);
+                       r = _do_dm_ioctl_unmangle_string(names->name, "name",
+                                                        buf, sizeof(buf),
+                                                        dm_get_name_mangling_mode());
+                       next = names->next;
+               } while (next);
+       }
+
+       return r;
+}
+
+static int _dm_ioctl_unmangle_uuids(int type, struct dm_ioctl *dmi)
+{
+       char buf[DM_UUID_LEN];
+       char *uuid = dmi->uuid;
+
+       if (uuid)
+               return _do_dm_ioctl_unmangle_string(uuid, "UUID", buf, sizeof(buf),
+                                                   dm_get_name_mangling_mode());
+
+       return 1;
+}
+
 static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
-                                    unsigned repeat_count)
+                                    unsigned buffer_repeat_count,
+                                    unsigned retry_repeat_count,
+                                    int *retryable)
 {
        struct dm_ioctl *dmi;
        int ioctl_with_uevent;
 
-       dmi = _flatten(dmt, repeat_count);
+       dmi = _flatten(dmt, buffer_repeat_count);
        if (!dmi) {
                log_error("Couldn't create ioctl argument.");
                return NULL;
@@ -1947,7 +1701,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
        }
 
        log_debug("dm %s %s%s %s%s%s %s%.0d%s%.0d%s"
-                 "%s%c%c%s%s %.0" PRIu64 " %s [%u]",
+                 "%s%c%c%s%s%s%s%s%s %.0" PRIu64 " %s [%u] (*%u)",
                  _cmd_data_v4[dmt->type].name,
                  dmt->new_uuid ? "UUID " : "",
                  dmi->name, dmi->uuid, dmt->newname ? " " : "",
@@ -1960,12 +1714,17 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
                  dmt->major > 0 ? ") " : "",
                  dmt->no_open_count ? 'N' : 'O',
                  dmt->no_flush ? 'N' : 'F',
+                 dmt->read_only ? "R" : "",
                  dmt->skip_lockfs ? "S " : "",
+                 dmt->retry_remove ? "T " : "",
+                 dmt->secure_data ? "W " : "",
                  dmt->query_inactive_table ? "I " : "",
+                 dmt->enable_checks ? "C" : "",
                  dmt->sector, _sanitise_message(dmt->message),
-                 dmi->data_size);
+                 dmi->data_size, retry_repeat_count);
 #ifdef DM_IOCTLS
-       if (ioctl(_control_fd, command, dmi) < 0) {
+       if (ioctl(_control_fd, command, dmi) < 0 &&
+           dmt->expected_errno != errno) {
                if (errno == ENXIO && ((dmt->type == DM_DEVICE_INFO) ||
                                       (dmt->type == DM_DEVICE_MKNODES) ||
                                       (dmt->type == DM_DEVICE_STATUS)))
@@ -1977,21 +1736,43 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
                                            _cmd_data_v4[dmt->type].name,
                                            strerror(errno));
                        else
-                               log_error("device-mapper: %s ioctl "
+                               log_error("device-mapper: %s ioctl on %s "
                                          "failed: %s",
-                                          _cmd_data_v4[dmt->type].name,
-                                         strerror(errno));
-                       _dm_zfree_dmi(dmi);
-                       return NULL;
+                                         _cmd_data_v4[dmt->type].name,
+                                         dmi->name, strerror(errno));
+
+                       /*
+                        * It's sometimes worth retrying after EBUSY in case
+                        * it's a transient failure caused by an asynchronous
+                        * process quickly scanning the device.
+                        */
+                       *retryable = errno == EBUSY;
+
+                       goto error;
                }
        }
 
-       if (ioctl_with_uevent && !_check_uevent_generated(dmi))
+       if (ioctl_with_uevent && dm_udev_get_sync_support() &&
+           !_check_uevent_generated(dmi)) {
+               log_debug("Uevent not generated! Calling udev_complete "
+                         "internally to avoid process lock-up.");
                _udev_complete(dmt);
+       }
+
+       if (!_dm_ioctl_unmangle_names(dmt->type, dmi))
+               goto error;
+
+       if (dmt->type != DM_DEVICE_REMOVE &&
+           !_dm_ioctl_unmangle_uuids(dmt->type, dmi))
+               goto error;
 
 #else /* Userspace alternative for testing */
 #endif
        return dmi;
+
+error:
+       _dm_zfree_dmi(dmi);
+       return NULL;
 }
 
 void dm_task_update_nodes(void)
@@ -1999,17 +1780,20 @@ void dm_task_update_nodes(void)
        update_devs();
 }
 
+#define DM_IOCTL_RETRIES 25
+#define DM_RETRY_USLEEP_DELAY 200000
+
 int dm_task_run(struct dm_task *dmt)
 {
        struct dm_ioctl *dmi;
        unsigned command;
        int check_udev;
-       int udev_only;
-
-#ifdef DM_COMPAT
-       if (_dm_version == 1)
-               return _dm_task_run_v1(dmt);
-#endif
+       int rely_on_udev;
+       int suspended_counter;
+       unsigned ioctl_retry = 1;
+       int retryable = 0;
+       const char *dev_name = DEV_NAME(dmt);
+       const char *dev_uuid = DEV_UUID(dmt);
 
        if ((unsigned) dmt->type >=
            (sizeof(_cmd_data_v4) / sizeof(*_cmd_data_v4))) {
@@ -2024,21 +1808,53 @@ int dm_task_run(struct dm_task *dmt)
        if (dmt->type == DM_DEVICE_CREATE && dmt->head)
                return _create_and_load_v4(dmt);
 
-       if (dmt->type == DM_DEVICE_MKNODES && !dmt->dev_name &&
-           !dmt->uuid && dmt->major <= 0)
+       if (dmt->type == DM_DEVICE_MKNODES && !dev_name &&
+           !dev_uuid && dmt->major <= 0)
                return _mknodes_v4(dmt);
 
        if ((dmt->type == DM_DEVICE_RELOAD) && dmt->suppress_identical_reload)
                return _reload_with_suppression_v4(dmt);
 
+       if ((dmt->type == DM_DEVICE_SUSPEND) && dmt->enable_checks)
+               return _suspend_with_validation_v4(dmt);
+
        if (!_open_control()) {
                _udev_complete(dmt);
-               return 0;
-       }
+               return_0;
+       }
+
+       if ((suspended_counter = dm_get_suspended_counter()) &&
+           dmt->type == DM_DEVICE_RELOAD)
+               log_error(INTERNAL_ERROR "Performing unsafe table load while %d device(s) "
+                         "are known to be suspended: "
+                         "%s%s%s %s%.0d%s%.0d%s%s",
+                         suspended_counter,
+                         dev_name ? : "",
+                         dev_uuid ? " UUID " : "",
+                         dev_uuid ? : "",
+                         dmt->major > 0 ? "(" : "",
+                         dmt->major > 0 ? dmt->major : 0,
+                         dmt->major > 0 ? ":" : "",
+                         dmt->minor > 0 ? dmt->minor : 0,
+                         dmt->major > 0 && dmt->minor == 0 ? "0" : "",
+                         dmt->major > 0 ? ") " : "");
 
        /* FIXME Detect and warn if cookie set but should not be. */
 repeat_ioctl:
-       if (!(dmi = _do_dm_ioctl(dmt, command, _ioctl_buffer_double_factor))) {
+       if (!(dmi = _do_dm_ioctl(dmt, command, _ioctl_buffer_double_factor,
+                                ioctl_retry, &retryable))) {
+               /*
+                * Async udev rules that scan devices commonly cause transient
+                * failures.  Normally you'd expect the user to have made sure
+                * nothing was using the device before issuing REMOVE, so it's
+                * worth retrying in case the failure is indeed transient.
+                */
+               if (retryable && dmt->type == DM_DEVICE_REMOVE &&
+                   dmt->retry_remove && ++ioctl_retry <= DM_IOCTL_RETRIES) {
+                       usleep(DM_RETRY_USLEEP_DELAY);
+                       goto repeat_ioctl;
+               }
+
                _udev_complete(dmt);
                return 0;
        }
@@ -2059,46 +1875,56 @@ repeat_ioctl:
                }
        }
 
+       /*
+        * Are we expecting a udev operation to occur that we need to check for?
+        */
        check_udev = dmt->cookie_set &&
                     !(dmt->event_nr >> DM_UDEV_FLAGS_SHIFT &
                       DM_UDEV_DISABLE_DM_RULES_FLAG);
 
-       udev_only = dmt->cookie_set ? (dmt->event_nr >> DM_UDEV_FLAGS_SHIFT &
-                                       DM_UDEV_DISABLE_LIBRARY_FALLBACK) : 0;
+       rely_on_udev = dmt->cookie_set ? (dmt->event_nr >> DM_UDEV_FLAGS_SHIFT &
+                                         DM_UDEV_DISABLE_LIBRARY_FALLBACK) : 0;
 
        switch (dmt->type) {
        case DM_DEVICE_CREATE:
-               if (dmt->dev_name && *dmt->dev_name && !udev_only)
-                       add_dev_node(dmt->dev_name, MAJOR(dmi->dev),
+               if ((dmt->add_node == DM_ADD_NODE_ON_CREATE) &&
+                   dev_name && *dev_name && !rely_on_udev)
+                       add_dev_node(dev_name, MAJOR(dmi->dev),
                                     MINOR(dmi->dev), dmt->uid, dmt->gid,
-                                    dmt->mode, check_udev);
+                                    dmt->mode, check_udev, rely_on_udev);
                break;
        case DM_DEVICE_REMOVE:
                /* FIXME Kernel needs to fill in dmi->name */
-               if (dmt->dev_name && !udev_only)
-                       rm_dev_node(dmt->dev_name, check_udev);
+               if (dev_name && !rely_on_udev)
+                       rm_dev_node(dev_name, check_udev, rely_on_udev);
                break;
 
        case DM_DEVICE_RENAME:
                /* FIXME Kernel needs to fill in dmi->name */
-               if (!dmt->new_uuid && dmt->dev_name && !udev_only)
-                       rename_dev_node(dmt->dev_name, dmt->newname,
-                                       check_udev);
+               if (!dmt->new_uuid && dev_name)
+                       rename_dev_node(dev_name, dmt->newname,
+                                       check_udev, rely_on_udev);
                break;
 
        case DM_DEVICE_RESUME:
+               if ((dmt->add_node == DM_ADD_NODE_ON_RESUME) &&
+                   dev_name && *dev_name)
+                       add_dev_node(dev_name, MAJOR(dmi->dev),
+                                    MINOR(dmi->dev), dmt->uid, dmt->gid,
+                                    dmt->mode, check_udev, rely_on_udev);
                /* FIXME Kernel needs to fill in dmi->name */
-               set_dev_node_read_ahead(dmt->dev_name, dmt->read_ahead,
-                                       dmt->read_ahead_flags);
+               set_dev_node_read_ahead(dev_name,
+                                       MAJOR(dmi->dev), MINOR(dmi->dev),
+                                       dmt->read_ahead, dmt->read_ahead_flags);
                break;
        
        case DM_DEVICE_MKNODES:
                if (dmi->flags & DM_EXISTS_FLAG)
                        add_dev_node(dmi->name, MAJOR(dmi->dev),
                                     MINOR(dmi->dev), dmt->uid,
-                                    dmt->gid, dmt->mode, 0);
-               else if (dmt->dev_name)
-                       rm_dev_node(dmt->dev_name, 0);
+                                    dmt->gid, dmt->mode, 0, rely_on_udev);
+               else if (dev_name)
+                       rm_dev_node(dev_name, 0, rely_on_udev);
                break;
 
        case DM_DEVICE_STATUS:
@@ -2129,6 +1955,15 @@ void dm_pools_check_leaks(void);
 
 void dm_lib_exit(void)
 {
+       int suspended_counter;
+       static unsigned _exited = 0;
+
+       if (_exited++)
+               return;
+
+       if ((suspended_counter = dm_get_suspended_counter()))
+               log_error("libdevmapper exiting with %d device(s) still suspended.", suspended_counter);
+
        dm_lib_release();
        selinux_release();
        if (_dm_bitset)
index d8cee45395d2693f690a639efa3194148c809ba7..8fc87389717676cc27ff0f5e2239552007ee8f63 100644 (file)
@@ -20,7 +20,6 @@
 #include <sys/types.h>
 
 struct dm_ioctl;
-struct dm_ioctl_v1;
 
 struct target {
        uint64_t start;
@@ -34,6 +33,7 @@ struct target {
 struct dm_task {
        int type;
        char *dev_name;
+       char *mangled_dev_name;
 
        struct target *head, *tail;
 
@@ -49,7 +49,6 @@ struct dm_task {
        uint32_t read_ahead_flags;
        union {
                struct dm_ioctl *v4;
-               struct dm_ioctl_v1 *v1;
        } dmi;
        char *newname;
        char *message;
@@ -60,11 +59,17 @@ struct dm_task {
        int skip_lockfs;
        int query_inactive_table;
        int suppress_identical_reload;
+       dm_add_node_t add_node;
        uint64_t existing_table_size;
        int cookie_set;
        int new_uuid;
+       int secure_data;
+       int retry_remove;
+       int enable_checks;
+       int expected_errno;
 
        char *uuid;
+       char *mangled_uuid;
 };
 
 struct cmd_data {
index 4aa99910b0c7f44d50ccf3919a4e6c0fa3bfcbdd..c853ab4e59cb22cf5df4fd37723f36cff236e520 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of the device-mapper userspace tools.
  *
@@ -19,6 +19,7 @@
 #include <inttypes.h>
 #include <stdarg.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 
 #ifdef linux
 #  include <linux/types.h>
@@ -74,6 +75,11 @@ void dm_log_init(dm_log_fn fn);
  */
 int dm_log_is_non_default(void);
 
+/*
+ * Number of devices currently in suspended state (via the library).
+ */
+int dm_get_suspended_counter(void);
+
 enum {
        DM_DEVICE_CREATE,
        DM_DEVICE_RELOAD,
@@ -158,13 +164,33 @@ struct dm_versions {
 int dm_get_library_version(char *version, size_t size);
 int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size);
 int dm_task_get_info(struct dm_task *dmt, struct dm_info *dmi);
-const char *dm_task_get_name(const struct dm_task *dmt);
+
+/*
+ * This function returns dm device's UUID based on the value
+ * of the mangling mode set during preceding dm_task_run call:
+ *   - unmangled UUID for DM_STRING_MANGLING_{AUTO, HEX},
+ *   - UUID without any changes for DM_STRING_MANGLING_NONE.
+ *
+ * To get mangled or unmangled form of the UUID directly, use
+ * dm_task_get_uuid_mangled or dm_task_get_uuid_unmangled function.
+ */
 const char *dm_task_get_uuid(const struct dm_task *dmt);
 
 struct dm_deps *dm_task_get_deps(struct dm_task *dmt);
-struct dm_names *dm_task_get_names(struct dm_task *dmt);
 struct dm_versions *dm_task_get_versions(struct dm_task *dmt);
 
+/*
+ * These functions return device-mapper names based on the value
+ * of the mangling mode set during preceding dm_task_run call:
+ *   - unmangled name for DM_STRING_MANGLING_{AUTO, HEX},
+ *   - name without any changes for DM_STRING_MANGLING_NONE.
+ *
+ * To get mangled or unmangled form of the name directly, use
+ * dm_task_get_name_mangled or dm_task_get_name_unmangled function.
+ */
+const char *dm_task_get_name(const struct dm_task *dmt);
+struct dm_names *dm_task_get_names(struct dm_task *dmt);
+
 int dm_task_set_ro(struct dm_task *dmt);
 int dm_task_set_newname(struct dm_task *dmt, const char *newname);
 int dm_task_set_newuuid(struct dm_task *dmt, const char *newuuid);
@@ -184,6 +210,19 @@ int dm_task_no_open_count(struct dm_task *dmt);
 int dm_task_skip_lockfs(struct dm_task *dmt);
 int dm_task_query_inactive_table(struct dm_task *dmt);
 int dm_task_suppress_identical_reload(struct dm_task *dmt);
+int dm_task_secure_data(struct dm_task *dmt);
+int dm_task_retry_remove(struct dm_task *dmt);
+
+/*
+ * Enable checks for common mistakes such as issuing ioctls in an unsafe order.
+ */
+int dm_task_enable_checks(struct dm_task *dmt);
+
+typedef enum {
+       DM_ADD_NODE_ON_RESUME, /* add /dev/mapper node with dmsetup resume */
+       DM_ADD_NODE_ON_CREATE  /* add /dev/mapper node with dmsetup create */
+} dm_add_node_t;
+int dm_task_set_add_node(struct dm_task *dmt, dm_add_node_t add_node);
 
 /*
  * Control read_ahead.
@@ -219,6 +258,30 @@ void *dm_get_next_target(struct dm_task *dmt,
                         void *next, uint64_t *start, uint64_t *length,
                         char **target_type, char **params);
 
+/* Parse params from STATUS call for thin_pool target */
+struct dm_pool;
+
+struct dm_status_thin_pool {
+       uint64_t transaction_id;
+       uint64_t used_metadata_blocks;
+       uint64_t total_metadata_blocks;
+       uint64_t used_data_blocks;
+       uint64_t total_data_blocks;
+       uint64_t held_metadata_root;
+};
+
+int dm_get_status_thin_pool(struct dm_pool *mem, const char *params,
+                           struct dm_status_thin_pool **status);
+
+/* Parse params from STATUS call for thin target */
+struct dm_status_thin {
+       uint64_t mapped_sectors;
+       uint64_t highest_mapped_sector;
+};
+
+int dm_get_status_thin(struct dm_pool *mem, const char *params,
+                      struct dm_status_thin **status);
+
 /*
  * Call this to actually run the ioctl.
  */
@@ -230,17 +293,96 @@ int dm_task_run(struct dm_task *dmt);
  */
 void dm_task_update_nodes(void);
 
+/*
+ * Mangling support
+ *
+ * Character whitelist: 0-9, A-Z, a-z, #+-.:=@_
+ * HEX mangling format: \xNN, NN being the hex value of the character.
+ * (whitelist and format supported by udev)
+*/
+typedef enum {
+       DM_STRING_MANGLING_NONE, /* do not mangle at all */
+       DM_STRING_MANGLING_AUTO, /* mangle only if not already mangled with hex, error when mixed */
+       DM_STRING_MANGLING_HEX   /* always mangle with hex encoding, no matter what the input is */
+} dm_string_mangling_t;
+
+/*
+ * Set/get mangling mode used for device-mapper names and uuids.
+ */
+int dm_set_name_mangling_mode(dm_string_mangling_t name_mangling);
+dm_string_mangling_t dm_get_name_mangling_mode(void);
+
+/*
+ * Get mangled/unmangled form of the device-mapper name or uuid
+ * irrespective of the global setting (set by dm_set_name_mangling_mode).
+ * The name or uuid returned needs to be freed after use by calling dm_free!
+ */
+char *dm_task_get_name_mangled(const struct dm_task *dmt);
+char *dm_task_get_name_unmangled(const struct dm_task *dmt);
+char *dm_task_get_uuid_mangled(const struct dm_task *dmt);
+char *dm_task_get_uuid_unmangled(const struct dm_task *dmt);
+
 /*
  * Configure the device-mapper directory
  */
 int dm_set_dev_dir(const char *dir);
 const char *dm_dir(void);
 
+/*
+ * Configure sysfs directory, /sys by default
+ */
+int dm_set_sysfs_dir(const char *dir);
+const char *dm_sysfs_dir(void);
+
+/*
+ * Configure default UUID prefix string.
+ * Conventionally this is a short capitalised prefix indicating the subsystem
+ * that is managing the devices, e.g. "LVM-" or "MPATH-".
+ * To support stacks of devices from different subsystems, recursive functions
+ * stop recursing if they reach a device with a different prefix.
+ */
+int dm_set_uuid_prefix(const char *uuid_prefix);
+const char *dm_uuid_prefix(void);
+
 /*
  * Determine whether a major number belongs to device-mapper or not.
  */
 int dm_is_dm_major(uint32_t major);
 
+/*
+ * Get associated device name for given major and minor number by reading
+ * the sysfs content. If this is a dm device, get associated dm name, the one
+ * that appears in /dev/mapper. DM names could be resolved this way only if
+ * kernel used >= 2.6.29, kernel name is found otherwise (e.g. dm-0).
+ * If prefer_kernel_name is set, the kernel name is always preferred over
+ * device-mapper name for dm devices no matter what the kernel version is.
+ * For non-dm devices, we always get associated kernel name, e.g sda, md0 etc.
+ * Returns 0 on error or if sysfs is not used (or configured incorrectly),
+ * otherwise returns 1 and the supplied buffer holds the device name.
+ */
+int dm_device_get_name(uint32_t major, uint32_t minor,
+                      int prefer_kernel_name,
+                      char *buf, size_t buf_size);
+
+/*
+ * Determine whether a device has any holders (devices
+ * using this device). If sysfs is not used (or configured
+ * incorrectly), returns 0.
+ */
+int dm_device_has_holders(uint32_t major, uint32_t minor);
+
+/*
+ * Determine whether a device contains mounted filesystem.
+ * If sysfs is not used (or configured incorrectly), returns 0.
+ */
+int dm_device_has_mounted_fs(uint32_t major, uint32_t minor);
+
+
+/*
+ * Initialise library
+ */
+void dm_lib_init(void) __attribute__((constructor));
+
 /*
  * Release library resources
  */
@@ -383,6 +525,11 @@ void dm_tree_skip_lockfs(struct dm_tree_node *dnode);
  */
 void dm_tree_use_no_flush_suspend(struct dm_tree_node *dnode);
 
+/*
+ * Retry removal of each device if not successful.
+ */
+void dm_tree_retry_remove(struct dm_tree_node *dnode);
+
 /*
  * Is the uuid prefix present in the tree?
  * Only returns 0 if every node was checked successfully.
@@ -450,6 +597,14 @@ int dm_tree_node_add_mirror_target_log(struct dm_tree_node *node,
                                          unsigned area_count,
                                          uint32_t flags);
 
+int dm_tree_node_add_raid_target(struct dm_tree_node *node,
+                                uint64_t size,
+                                const char *raid_type,
+                                uint32_t region_size,
+                                uint32_t stripe_size,
+                                uint64_t rebuilds,
+                                uint64_t flags);
+
 /*
  * Replicator operation mode
  * Note: API for Replicator is not yet stable
@@ -484,6 +639,63 @@ int dm_tree_node_add_replicator_dev_target(struct dm_tree_node *node,
                                           uint32_t slog_region_size);
 /* End of Replicator API */
 
+/*
+ * FIXME: Defines bellow are based on kernel's dm-thin.c defines
+ * DATA_DEV_BLOCK_SIZE_MIN_SECTORS (64 * 1024 >> SECTOR_SHIFT)
+ * DATA_DEV_BLOCK_SIZE_MAX_SECTORS (1024 * 1024 * 1024 >> SECTOR_SHIFT)
+ */
+#define DM_THIN_MIN_DATA_BLOCK_SIZE (UINT32_C(128))
+#define DM_THIN_MAX_DATA_BLOCK_SIZE (UINT32_C(2097152))
+
+int dm_tree_node_add_thin_pool_target(struct dm_tree_node *node,
+                                     uint64_t size,
+                                     uint64_t transaction_id,
+                                     const char *metadata_uuid,
+                                     const char *pool_uuid,
+                                     uint32_t data_block_size,
+                                     uint64_t low_water_mark,
+                                     unsigned skip_block_zeroing);
+
+/* Supported messages for thin provision target */
+typedef enum {
+       DM_THIN_MESSAGE_CREATE_SNAP,            /* device_id, origin_id */
+       DM_THIN_MESSAGE_CREATE_THIN,            /* device_id */
+       DM_THIN_MESSAGE_DELETE,                 /* device_id */
+       DM_THIN_MESSAGE_SET_TRANSACTION_ID,     /* current_id, new_id */
+       DM_THIN_MESSAGE_RESERVE_METADATA_SNAP,  /* target version >= 1.1 */
+       DM_THIN_MESSAGE_RELEASE_METADATA_SNAP,  /* target version >= 1.1 */
+} dm_thin_message_t;
+
+int dm_tree_node_add_thin_pool_message(struct dm_tree_node *node,
+                                      dm_thin_message_t type,
+                                      uint64_t id1, uint64_t id2);
+
+/*
+ * Set thin pool discard features
+ *   ignore      - Disable support for discards
+ *   no_passdown - Don't pass discards down to underlying data device,
+ *                 just remove the mapping
+ * Feature is available since version 1.1 of the thin target.
+ */
+int dm_tree_node_set_thin_pool_discard(struct dm_tree_node *node,
+                                      unsigned ignore,
+                                      unsigned no_passdown);
+
+/*
+ * FIXME: Defines bellow are based on kernel's dm-thin.c defines
+ * MAX_DEV_ID ((1 << 24) - 1)
+ */
+#define DM_THIN_MAX_DEVICE_ID (UINT32_C((1 << 24) - 1))
+int dm_tree_node_add_thin_target(struct dm_tree_node *node,
+                                uint64_t size,
+                                const char *pool_uuid,
+                                uint32_t device_id);
+
+int dm_tree_node_set_thin_external_origin(struct dm_tree_node *node,
+                                         const char *external_uuid);
+
+void dm_tree_node_set_udev_flags(struct dm_tree_node *node, uint16_t udev_flags);
+
 void dm_tree_node_set_presuspend_node(struct dm_tree_node *node,
                                      struct dm_tree_node *presuspend_node);
 
@@ -492,6 +704,11 @@ int dm_tree_node_add_target_area(struct dm_tree_node *node,
                                    const char *dlid,
                                    uint64_t offset);
 
+/*
+ * Only for temporarily-missing raid devices where changes are tracked.
+ */
+int dm_tree_node_add_null_area(struct dm_tree_node *node, uint64_t offset);
+
 /*
  * Set readahead (in sectors) after loading the node.
  */
@@ -499,6 +716,20 @@ void dm_tree_node_set_read_ahead(struct dm_tree_node *dnode,
                                 uint32_t read_ahead,
                                 uint32_t read_ahead_flags);
 
+/*
+ * Set node callback hook before de/activation.
+ * Callback is called before 'activation' of node for activation tree,
+ * or 'deactivation' of node for deactivation tree.
+ */
+typedef enum {
+       DM_NODE_CALLBACK_PRELOADED,   /* Node has preload deps */
+       DM_NODE_CALLBACK_DEACTIVATED, /* Node is deactivated */
+} dm_node_callback_t;
+typedef int (*dm_node_callback_fn) (struct dm_tree_node *node,
+                                   dm_node_callback_t type, void *cb_data);
+void dm_tree_node_set_callback(struct dm_tree_node *node,
+                              dm_node_callback_fn cb, void *cb_data);
+
 void dm_tree_set_cookie(struct dm_tree_node *node, uint32_t cookie);
 uint32_t dm_tree_get_cookie(struct dm_tree_node *node);
 
@@ -510,13 +741,19 @@ uint32_t dm_tree_get_cookie(struct dm_tree_node *node);
  * Memory management
  *******************/
 
-void *dm_malloc_aux(size_t s, const char *file, int line);
-void *dm_malloc_aux_debug(size_t s, const char *file, int line);
-void *dm_zalloc_aux(size_t s, const char *file, int line);
-void *dm_zalloc_aux_debug(size_t s, const char *file, int line);
-char *dm_strdup_aux(const char *str, const char *file, int line);
+void *dm_malloc_aux(size_t s, const char *file, int line)
+       __attribute__((malloc)) __attribute__((__warn_unused_result__));
+void *dm_malloc_aux_debug(size_t s, const char *file, int line)
+       __attribute__((__warn_unused_result__));
+void *dm_zalloc_aux(size_t s, const char *file, int line)
+       __attribute__((malloc)) __attribute__((__warn_unused_result__));
+void *dm_zalloc_aux_debug(size_t s, const char *file, int line)
+       __attribute__((__warn_unused_result__));
+char *dm_strdup_aux(const char *str, const char *file, int line)
+       __attribute__((malloc)) __attribute__((__warn_unused_result__));
 void dm_free_aux(void *p);
-void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line);
+void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line)
+       __attribute__((__warn_unused_result__));
 int dm_dump_memory_debug(void);
 void dm_bounds_check_debug(void);
 
@@ -579,15 +816,34 @@ void dm_bounds_check_debug(void);
 struct dm_pool;
 
 /* constructor and destructor */
-struct dm_pool *dm_pool_create(const char *name, size_t chunk_hint);
+struct dm_pool *dm_pool_create(const char *name, size_t chunk_hint)
+       __attribute__((__warn_unused_result__));
 void dm_pool_destroy(struct dm_pool *p);
 
 /* simple allocation/free routines */
-void *dm_pool_alloc(struct dm_pool *p, size_t s);
-void *dm_pool_alloc_aligned(struct dm_pool *p, size_t s, unsigned alignment);
+void *dm_pool_alloc(struct dm_pool *p, size_t s)
+       __attribute__((__warn_unused_result__));
+void *dm_pool_alloc_aligned(struct dm_pool *p, size_t s, unsigned alignment)
+       __attribute__((__warn_unused_result__));
 void dm_pool_empty(struct dm_pool *p);
 void dm_pool_free(struct dm_pool *p, void *ptr);
 
+/*
+ * To aid debugging, a pool can be locked. Any modifications made
+ * to the content of the pool while it is locked can be detected.
+ * Default compilation is using a crc checksum to notice modifications.
+ * The pool locking is using the mprotect with the compilation flag
+ * DEBUG_ENFORCE_POOL_LOCKING to enforce the memory protection.
+ */
+/* query pool lock status */
+int dm_pool_locked(struct dm_pool *p);
+/* mark pool as locked */
+int dm_pool_lock(struct dm_pool *p, int crc)
+       __attribute__((__warn_unused_result__));
+/* mark pool as unlocked */
+int dm_pool_unlock(struct dm_pool *p, int crc)
+       __attribute__((__warn_unused_result__));
+
 /*
  * Object building routines:
  *
@@ -639,9 +895,12 @@ void *dm_pool_end_object(struct dm_pool *p);
 void dm_pool_abandon_object(struct dm_pool *p);
 
 /* utilities */
-char *dm_pool_strdup(struct dm_pool *p, const char *str);
-char *dm_pool_strndup(struct dm_pool *p, const char *str, size_t n);
-void *dm_pool_zalloc(struct dm_pool *p, size_t s);
+char *dm_pool_strdup(struct dm_pool *p, const char *str)
+       __attribute__((__warn_unused_result__));
+char *dm_pool_strndup(struct dm_pool *p, const char *str, size_t n)
+       __attribute__((__warn_unused_result__));
+void *dm_pool_zalloc(struct dm_pool *p, size_t s)
+       __attribute__((__warn_unused_result__));
 
 /******************
  * bitset functions
@@ -699,7 +958,8 @@ struct dm_hash_node;
 
 typedef void (*dm_hash_iterate_fn) (void *data);
 
-struct dm_hash_table *dm_hash_create(unsigned size_hint);
+struct dm_hash_table *dm_hash_create(unsigned size_hint)
+       __attribute__((__warn_unused_result__));
 void dm_hash_destroy(struct dm_hash_table *t);
 void dm_hash_wipe(struct dm_hash_table *t);
 
@@ -707,10 +967,10 @@ void *dm_hash_lookup(struct dm_hash_table *t, const char *key);
 int dm_hash_insert(struct dm_hash_table *t, const char *key, void *data);
 void dm_hash_remove(struct dm_hash_table *t, const char *key);
 
-void *dm_hash_lookup_binary(struct dm_hash_table *t, const char *key, uint32_t len);
-int dm_hash_insert_binary(struct dm_hash_table *t, const char *key, uint32_t len,
+void *dm_hash_lookup_binary(struct dm_hash_table *t, const void *key, uint32_t len);
+int dm_hash_insert_binary(struct dm_hash_table *t, const void *key, uint32_t len,
                       void *data);
-void dm_hash_remove_binary(struct dm_hash_table *t, const char *key, uint32_t len);
+void dm_hash_remove_binary(struct dm_hash_table *t, const void *key, uint32_t len);
 
 unsigned dm_hash_get_num_entries(struct dm_hash_table *t);
 void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f);
@@ -770,7 +1030,7 @@ void dm_list_del(struct dm_list *elem);
 void dm_list_move(struct dm_list *head, struct dm_list *elem);
 
 /*
- * Join 'head1' to the of 'head'.
+ * Join 'head1' to the end of 'head'.
  */
 void dm_list_splice(struct dm_list *head, struct dm_list *head1);
 
@@ -968,6 +1228,52 @@ int dm_snprintf(char *buf, size_t bufsize, const char *format, ...)
  */
 const char *dm_basename(const char *path);
 
+/*
+ * Returns number of occurrences of 'c' in 'str' of length 'size'.
+ */
+unsigned dm_count_chars(const char *str, size_t len, const int c);
+
+/*
+ * Length of string after escaping double quotes and backslashes.
+ */
+size_t dm_escaped_len(const char *str);
+
+/*
+ * <vg>-<lv>-<layer> or if !layer just <vg>-<lv>.
+ */
+char *dm_build_dm_name(struct dm_pool *mem, const char *vgname,
+                      const char *lvname, const char *layer);
+char *dm_build_dm_uuid(struct dm_pool *mem, const char *prefix, const char *lvid, const char *layer);
+
+/*
+ * Copies a string, quoting double quotes with backslashes.
+ */
+char *dm_escape_double_quotes(char *out, const char *src);
+
+/*
+ * Undo quoting in situ.
+ */
+void dm_unescape_double_quotes(char *src);
+
+/*
+ * Unescape colons and "at" signs in situ and save the substrings
+ * starting at the position of the first unescaped colon and the
+ * first unescaped "at" sign. This is normally used to unescape
+ * device names used as PVs.
+ */
+void dm_unescape_colons_and_at_signs(char *src,
+                                    char **substr_first_unquoted_colon,
+                                    char **substr_first_unquoted_at_sign);
+
+/*
+ * Replacement for strncpy() function.
+ *
+ * Copies no more than n bytes from string pointed by src to the buffer
+ * pointed by dest and ensure string is finished with '\0'.
+ * Returns 0 if the whole string does not fit.
+ */
+int dm_strncpy(char *dest, const char *src, size_t n);
+
 /**************************
  * file/stream manipulation
  **************************/
@@ -978,6 +1284,8 @@ const char *dm_basename(const char *path);
  */
 int dm_create_dir(const char *dir);
 
+int dm_is_empty_dir(const char *dir);
+
 /*
  * Close a stream, with nicer error checking than fclose's.
  * Derived from gnulib's close-stream.c.
@@ -995,6 +1303,7 @@ int dm_fclose(FILE *stream);
  */
 int dm_asprintf(char **buf, const char *format, ...)
     __attribute__ ((format(printf, 2, 3)));
+int dm_vasprintf(char **buf, const char *format, va_list ap);
 
 /*
  * create lockfile (pidfile) - create and lock a lock file
@@ -1117,7 +1426,7 @@ int dm_report_set_output_field_name_prefix(struct dm_report *rh,
  * They take care of allocating copies of the data.
  */
 int dm_report_field_string(struct dm_report *rh, struct dm_report_field *field,
-                          const char **data);
+                          const char *const *data);
 int dm_report_field_int32(struct dm_report *rh, struct dm_report_field *field,
                          const int32_t *data);
 int dm_report_field_uint32(struct dm_report *rh, struct dm_report_field *field,
@@ -1135,7 +1444,112 @@ int dm_report_field_uint64(struct dm_report *rh, struct dm_report_field *field,
 void dm_report_field_set_value(struct dm_report_field *field, const void *value,
                               const void *sortvalue);
 
+/*************************
+ * config file parse/print
+ *************************/
+typedef enum {
+       DM_CFG_INT,
+       DM_CFG_FLOAT,
+       DM_CFG_STRING,
+       DM_CFG_EMPTY_ARRAY
+} dm_config_value_type_t;
+
+struct dm_config_value {
+       dm_config_value_type_t type;
+
+       union {
+               int64_t i;
+               float f;
+               double d;               /* Unused. */
+               const char *str;
+       } v;
+
+       struct dm_config_value *next;   /* For arrays */
+};
+
+struct dm_config_node {
+       const char *key;
+       struct dm_config_node *parent, *sib, *child;
+       struct dm_config_value *v;
+};
+
+struct dm_config_tree {
+       struct dm_config_node *root;
+       struct dm_config_tree *cascade;
+       struct dm_pool *mem;
+       void *custom;
+};
+
+struct dm_config_tree *dm_config_create(void);
+struct dm_config_tree *dm_config_from_string(const char *config_settings);
+int dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end);
+
+void *dm_config_get_custom(struct dm_config_tree *cft);
+void dm_config_set_custom(struct dm_config_tree *cft, void *custom);
+
+/*
+ * When searching, first_cft is checked before second_cft.
+ */
+struct dm_config_tree *dm_config_insert_cascaded_tree(struct dm_config_tree *first_cft, struct dm_config_tree *second_cft);
+
+/*
+ * If there's a cascaded dm_config_tree, remove the top layer
+ * and return the layer below.  Otherwise return NULL.
+ */
+struct dm_config_tree *dm_config_remove_cascaded_tree(struct dm_config_tree *cft);
+
+void dm_config_destroy(struct dm_config_tree *cft);
+
+typedef int (*dm_putline_fn)(const char *line, void *baton);
+/* Write the node and any subsequent siblings it has. */
+int dm_config_write_node(const struct dm_config_node *cn, dm_putline_fn putline, void *baton);
+/* Write given node only without subsequent siblings. */
+int dm_config_write_one_node(const struct dm_config_node *cn, dm_putline_fn putline, void *baton);
+
+struct dm_config_node *dm_config_find_node(const struct dm_config_node *cn, const char *path);
+int dm_config_has_node(const struct dm_config_node *cn, const char *path);
+const char *dm_config_find_str(const struct dm_config_node *cn, const char *path, const char *fail);
+const char *dm_config_find_str_allow_empty(const struct dm_config_node *cn, const char *path, const char *fail);
+int dm_config_find_int(const struct dm_config_node *cn, const char *path, int fail);
+int64_t dm_config_find_int64(const struct dm_config_node *cn, const char *path, int64_t fail);
+float dm_config_find_float(const struct dm_config_node *cn, const char *path, float fail);
+
+const struct dm_config_node *dm_config_tree_find_node(const struct dm_config_tree *cft, const char *path);
+const char *dm_config_tree_find_str(const struct dm_config_tree *cft, const char *path, const char *fail);
+const char *dm_config_tree_find_str_allow_empty(const struct dm_config_tree *cft, const char *path, const char *fail);
+int dm_config_tree_find_int(const struct dm_config_tree *cft, const char *path, int fail);
+int64_t dm_config_tree_find_int64(const struct dm_config_tree *cft, const char *path, int64_t fail);
+float dm_config_tree_find_float(const struct dm_config_tree *cft, const char *path, float fail);
+int dm_config_tree_find_bool(const struct dm_config_tree *cft, const char *path, int fail);
+
+/*
+ * Understands (0, ~0), (y, n), (yes, no), (on,
+ * off), (true, false).
+ */
+int dm_config_find_bool(const struct dm_config_node *cn, const char *path, int fail);
+
+int dm_config_get_uint32(const struct dm_config_node *cn, const char *path, uint32_t *result);
+int dm_config_get_uint64(const struct dm_config_node *cn, const char *path, uint64_t *result);
+int dm_config_get_str(const struct dm_config_node *cn, const char *path, const char **result);
+int dm_config_get_list(const struct dm_config_node *cn, const char *path, const struct dm_config_value **result);
+int dm_config_get_section(const struct dm_config_node *cn, const char *path, const struct dm_config_node **result);
+
+unsigned dm_config_maybe_section(const char *str, unsigned len);
+
+const char *dm_config_parent_name(const struct dm_config_node *n);
+
+struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem, const struct dm_config_node *node, int siblings);
+struct dm_config_node *dm_config_create_node(struct dm_config_tree *cft, const char *key);
+struct dm_config_value *dm_config_create_value(struct dm_config_tree *cft);
+struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, const struct dm_config_node *cn, int siblings);
+
+struct dm_pool *dm_config_memory(struct dm_config_tree *cft);
+
+/* Udev device directory. */
+#define DM_UDEV_DEV_DIR "/dev/"
+
 /* Cookie prefixes.
+ *
  * The cookie value consists of a prefix (16 bits) and a base (16 bits).
  * We can use the prefix to store the flags. These flags are sent to
  * kernel within given dm task. When returned back to userspace in
@@ -1143,6 +1557,7 @@ void dm_report_field_set_value(struct dm_report_field *field, const void *value,
  * of udev rules we use by decoding the cookie prefix. When doing the
  * notification, we replace the cookie prefix with DM_COOKIE_MAGIC,
  * so we notify the right semaphore.
+ *
  * It is still possible to use cookies for passing the flags to udev
  * rules even when udev_sync is disabled. The base part of the cookie
  * will be zero (there's no notification semaphore) and prefix will be
@@ -1214,11 +1629,17 @@ void dm_udev_set_sync_support(int sync_with_udev);
 int dm_udev_get_sync_support(void);
 void dm_udev_set_checking(int checking);
 int dm_udev_get_checking(void);
+
+/*
+ * Default value to get new auto generated cookie created
+ */
+#define DM_COOKIE_AUTO_CREATE 0
 int dm_udev_create_cookie(uint32_t *cookie);
 int dm_udev_complete(uint32_t cookie);
 int dm_udev_wait(uint32_t cookie);
 
 #define DM_DEV_DIR_UMASK 0022
+#define DM_CONTROL_NODE_UMASK 0177
 
 #ifdef __cplusplus
 }
index 6d8bcbd8afcaf569e58deb12c8dfb6f65586040f..b8533ed6d81ae2b15fd0353b5cd715ff47de920d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of the device-mapper userspace tools.
  *
@@ -29,7 +29,6 @@
 #  include <sys/types.h>
 #  include <sys/ipc.h>
 #  include <sys/sem.h>
-#  define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
 #  include <libudev.h>
 #endif
 
@@ -44,6 +43,8 @@
 #  include <selinux/label.h>
 #endif
 
+#define DM_DEFAULT_NAME_MANGLING_MODE_ENV_VAR_NAME "DM_DEFAULT_NAME_MANGLING_MODE"
+
 #define DEV_DIR "/dev/"
 
 #ifdef UDEV_SYNC_SUPPORT
@@ -59,8 +60,15 @@ union semun
 #endif
 
 static char _dm_dir[PATH_MAX] = DEV_DIR DM_DIR;
+static char _sysfs_dir[PATH_MAX] = "/sys/";
+static char _path0[PATH_MAX];           /* path buffer, safe 4kB on stack */
+
+#define DM_MAX_UUID_PREFIX_LEN 15
+static char _default_uuid_prefix[DM_MAX_UUID_PREFIX_LEN + 1] = "LVM-";
 
 static int _verbose = 0;
+static int _suspended_dev_counter = 0;
+static dm_string_mangling_t _name_mangling_mode = DEFAULT_DM_NAME_MANGLING;
 
 #ifdef HAVE_SELINUX_LABEL_H
 static struct selabel_handle *_selabel_handle = NULL;
@@ -73,11 +81,28 @@ static int _sync_with_udev = 1;
 static int _udev_checking = 1;
 #endif
 
+void dm_lib_init(void)
+{
+       const char *env;
+
+       env = getenv(DM_DEFAULT_NAME_MANGLING_MODE_ENV_VAR_NAME);
+       if (env && *env) {
+               if (!strcasecmp(env, "none"))
+                       _name_mangling_mode = DM_STRING_MANGLING_NONE;
+               else if (!strcasecmp(env, "auto"))
+                       _name_mangling_mode = DM_STRING_MANGLING_AUTO;
+               else if (!strcasecmp(env, "hex"))
+                       _name_mangling_mode = DM_STRING_MANGLING_HEX;
+       } else
+               _name_mangling_mode = DEFAULT_DM_NAME_MANGLING;
+}
+
 /*
  * Library users can provide their own logging
  * function.
  */
 
+__attribute__((format(printf, 5, 0)))
 static void _default_log_line(int level,
            const char *file __attribute__((unused)),
            int line __attribute__((unused)), int dm_errno, 
@@ -101,6 +126,7 @@ static void _default_log_line(int level,
                fprintf(use_stderr ? stderr : stdout, "\n");
 }
 
+__attribute__((format(printf, 5, 6)))
 static void _default_log_with_errno(int level,
            const char *file __attribute__((unused)),
            int line __attribute__((unused)), int dm_errno, 
@@ -113,6 +139,7 @@ static void _default_log_with_errno(int level,
        va_end(ap);
 }
 
+__attribute__((format(printf, 4, 5)))
 static void _default_log(int level, const char *file,
                         int line, const char *f, ...)
 {
@@ -171,6 +198,40 @@ int dm_get_library_version(char *version, size_t size)
        return 1;
 }
 
+void inc_suspended(void)
+{
+       _suspended_dev_counter++;
+       log_debug("Suspended device counter increased to %d", _suspended_dev_counter);
+}
+
+void dec_suspended(void)
+{
+       if (!_suspended_dev_counter) {
+               log_error("Attempted to decrement suspended device counter below zero.");
+               return;
+       }
+
+       _suspended_dev_counter--;
+       log_debug("Suspended device counter reduced to %d", _suspended_dev_counter);
+}
+
+int dm_get_suspended_counter(void)
+{
+       return _suspended_dev_counter;
+}
+
+int dm_set_name_mangling_mode(dm_string_mangling_t name_mangling_mode)
+{
+       _name_mangling_mode = name_mangling_mode;
+
+       return 1;
+}
+
+dm_string_mangling_t dm_get_name_mangling_mode(void)
+{
+       return _name_mangling_mode;
+}
+
 struct dm_task *dm_task_create(int type)
 {
        struct dm_task *dmt = dm_zalloc(sizeof(*dmt));
@@ -183,7 +244,7 @@ struct dm_task *dm_task_create(int type)
 
        if (!dm_check_version()) {
                dm_free(dmt);
-               return NULL;
+               return_NULL;
        }
 
        dmt->type = type;
@@ -200,6 +261,7 @@ struct dm_task *dm_task_create(int type)
        dmt->cookie_set = 0;
        dmt->query_inactive_table = 0;
        dmt->new_uuid = 0;
+       dmt->secure_data = 0;
 
        return dmt;
 }
@@ -207,18 +269,18 @@ struct dm_task *dm_task_create(int type)
 /*
  * Find the name associated with a given device number by scanning _dm_dir.
  */
-static char *_find_dm_name_of_device(dev_t st_rdev)
+static int _find_dm_name_of_device(dev_t st_rdev, char *buf, size_t buf_len)
 {
        const char *name;
        char path[PATH_MAX];
        struct dirent *dirent;
        DIR *d;
-       struct stat buf;
-       char *new_name = NULL;
+       struct stat st;
+       int r = 0;
 
        if (!(d = opendir(_dm_dir))) {
                log_sys_error("opendir", _dm_dir);
-               return NULL;
+               return 0;
        }
 
        while ((dirent = readdir(d))) {
@@ -233,13 +295,12 @@ static char *_find_dm_name_of_device(dev_t st_rdev)
                        continue;
                }
 
-               if (stat(path, &buf))
+               if (stat(path, &st))
                        continue;
 
-               if (buf.st_rdev == st_rdev) {
-                       if (!(new_name = dm_strdup(name)))
-                               log_error("dm_task_set_name: strdup(%s) failed",
-                                         name);
+               if (st.st_rdev == st_rdev) {
+                       strncpy(buf, name, buf_len);
+                       r = 1;
                        break;
                }
        }
@@ -247,73 +308,444 @@ static char *_find_dm_name_of_device(dev_t st_rdev)
        if (closedir(d))
                log_sys_error("closedir", _dm_dir);
 
-       return new_name;
+       return r;
 }
 
-int dm_task_set_name(struct dm_task *dmt, const char *name)
+static int _is_whitelisted_char(char c)
 {
-       char *pos;
-       char *new_name = NULL;
-       char path[PATH_MAX];
-       struct stat st1, st2;
-
-       dm_free(dmt->dev_name);
-       dmt->dev_name = NULL;
-
        /*
-        * Path supplied for existing device?
+        * Actually, DM supports any character in a device name.
+        * This whitelist is just for proper integration with udev.
         */
-       if ((pos = strrchr(name, '/'))) {
-               if (dmt->type == DM_DEVICE_CREATE) {
-                       log_error("Name \"%s\" invalid. It contains \"/\".", name);
-                       return 0;
+        if ((c >= '0' && c <= '9') ||
+            (c >= 'A' && c <= 'Z') ||
+            (c >= 'a' && c <= 'z') ||
+            strchr("#+-.:=@_", c) != NULL)
+                return 1;
+
+        return 0;
+}
+
+int check_multiple_mangled_string_allowed(const char *str, const char *str_name,
+                                        dm_string_mangling_t mode)
+{
+       if (mode == DM_STRING_MANGLING_AUTO && strstr(str, "\\x5cx")) {
+               log_error("The %s \"%s\" seems to be mangled more than once. "
+                         "This is not allowed in auto mode.", str_name, str);
+               return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * Mangle all characters in the input string which are not on a whitelist
+ * with '\xNN' format where NN is the hex value of the character.
+ */
+int mangle_string(const char *str, const char *str_name, size_t len,
+                 char *buf, size_t buf_len, dm_string_mangling_t mode)
+{
+       int need_mangling = -1; /* -1 don't know yet, 0 no, 1 yes */
+       size_t i, j;
+
+       if (!str || !buf)
+               return -1;
+
+       /* Is there anything to do at all? */
+       if (!*str || !len)
+               return 0;
+
+       if (buf_len < DM_NAME_LEN) {
+               log_error(INTERNAL_ERROR "mangle_string: supplied buffer too small");
+               return -1;
+       }
+
+       if (mode == DM_STRING_MANGLING_NONE)
+               mode = DM_STRING_MANGLING_AUTO;
+
+       for (i = 0, j = 0; str[i]; i++) {
+               if (mode == DM_STRING_MANGLING_AUTO) {
+                       /*
+                        * Detect already mangled part of the string and keep it.
+                        * Return error on mixture of mangled/not mangled!
+                        */
+                       if (str[i] == '\\' && str[i+1] == 'x') {
+                               if ((len - i < 4) || (need_mangling == 1))
+                                       goto bad1;
+                               if (buf_len - j < 4)
+                                       goto bad2;
+
+                               memcpy(&buf[j], &str[i], 4);
+                               i+=3; j+=4;
+
+                               need_mangling = 0;
+                               continue;
+                       }
                }
 
-               if (stat(name, &st1)) {
-                       log_error("Device %s not found", name);
-                       return 0;
+               if (_is_whitelisted_char(str[i])) {
+                       /* whitelisted, keep it. */
+                       if (buf_len - j < 1)
+                               goto bad2;
+                       buf[j] = str[i];
+                       j++;
+               } else {
+                       /*
+                        * Not on a whitelist, mangle it.
+                        * Return error on mixture of mangled/not mangled
+                        * unless a DM_STRING_MANGLING_HEX is used!.
+                        */
+                       if ((mode != DM_STRING_MANGLING_HEX) && (need_mangling == 0))
+                               goto bad1;
+                       if (buf_len - j < 4)
+                               goto bad2;
+
+                       sprintf(&buf[j], "\\x%02x", (unsigned char) str[i]);
+                       j+=4;
+
+                       need_mangling = 1;
                }
+       }
 
-               /*
-                * If supplied path points to same device as last component
-                * under /dev/mapper, use that name directly.  Otherwise call
-                * _find_dm_name_of_device() to scan _dm_dir for a match.
-                */
-               if (dm_snprintf(path, sizeof(path), "%s/%s", _dm_dir,
-                               pos + 1) == -1) {
-                       log_error("Couldn't create path for %s", pos + 1);
-                       return 0;
+       if (buf_len - j < 1)
+               goto bad2;
+       buf[j] = '\0';
+
+       /* All chars in the string whitelisted? */
+       if (need_mangling == -1)
+               need_mangling = 0;
+
+       return need_mangling;
+
+bad1:
+       log_error("The %s \"%s\" contains mixed mangled and unmangled "
+                 "characters or it's already mangled improperly.", str_name, str);
+       return -1;
+bad2:
+       log_error("Mangled form of the %s too long for \"%s\".", str_name, str);
+       return -1;
+}
+
+/*
+ * Try to unmangle supplied string.
+ * Return value: -1 on error, 0 when no unmangling needed, 1 when unmangling applied
+ */
+int unmangle_string(const char *str, const char *str_name, size_t len,
+                   char *buf, size_t buf_len, dm_string_mangling_t mode)
+{
+       int strict = mode != DM_STRING_MANGLING_NONE;
+       char str_rest[DM_NAME_LEN];
+       size_t i, j;
+       int code;
+       int r = 0;
+
+       if (!str || !buf)
+               return -1;
+
+       /* Is there anything to do at all? */
+       if (!*str || !len)
+               return 0;
+
+       if (buf_len < DM_NAME_LEN) {
+               log_error(INTERNAL_ERROR "unmangle_string: supplied buffer too small");
+               return -1;
+       }
+
+       for (i = 0, j = 0; str[i]; i++, j++) {
+               if (strict && !(_is_whitelisted_char(str[i]) || str[i]=='\\')) {
+                       log_error("The %s \"%s\" should be mangled but "
+                                 "it contains blacklisted characters.", str_name, str);
+                       j=0; r=-1;
+                       goto out;
                }
 
-               if (!stat(path, &st2) && (st1.st_rdev == st2.st_rdev))
-                       name = pos + 1;
-               else if ((new_name = _find_dm_name_of_device(st1.st_rdev)))
-                       name = new_name;
-               else {
-                       log_error("Device %s not found", name);
+               if (str[i] == '\\' && str[i+1] == 'x') {
+                       if (!sscanf(&str[i+2], "%2x%s", &code, str_rest)) {
+                               log_debug("Hex encoding mismatch detected in %s \"%s\" "
+                                         "while trying to unmangle it.", str_name, str);
+                               goto out;
+                       }
+                       buf[j] = (unsigned char) code;
+
+                       /* skip the encoded part we've just decoded! */
+                       i+= 3;
+
+                       /* unmangling applied */
+                       r = 1;
+               } else
+                       buf[j] = str[i];
+       }
+
+out:
+       buf[j] = '\0';
+       return r;
+}
+
+static int _dm_task_set_name(struct dm_task *dmt, const char *name,
+                            dm_string_mangling_t mangling_mode)
+{
+       char mangled_name[DM_NAME_LEN];
+       int r = 0;
+
+       dm_free(dmt->dev_name);
+       dmt->dev_name = NULL;
+       dm_free(dmt->mangled_dev_name);
+       dmt->mangled_dev_name = NULL;
+
+       if (strlen(name) >= DM_NAME_LEN) {
+               log_error("Name \"%s\" too long.", name);
+               return 0;
+       }
+
+       if (!check_multiple_mangled_string_allowed(name, "name", mangling_mode))
+               return_0;
+
+       if (mangling_mode != DM_STRING_MANGLING_NONE &&
+           (r = mangle_string(name, "name", strlen(name), mangled_name,
+                              sizeof(mangled_name), mangling_mode)) < 0) {
+               log_error("Failed to mangle device name \"%s\".", name);
+               return 0;
+       }
+
+       /* Store mangled_dev_name only if it differs from dev_name! */
+       if (r) {
+               log_debug("Device name mangled [%s]: %s --> %s",
+                         mangling_mode == DM_STRING_MANGLING_AUTO ? "auto" : "hex",
+                         name, mangled_name);
+               if (!(dmt->mangled_dev_name = dm_strdup(mangled_name))) {
+                       log_error("_dm_task_set_name: dm_strdup(%s) failed", mangled_name);
                        return 0;
                }
        }
 
-       if (strlen(name) >= DM_NAME_LEN) {
-               log_error("Name \"%s\" too long", name);
-               dm_free(new_name);
+       if (!(dmt->dev_name = dm_strdup(name))) {
+               log_error("_dm_task_set_name: strdup(%s) failed", name);
+               return 0;
+       }
+
+       return 1;
+}
+
+static int _dm_task_set_name_from_path(struct dm_task *dmt, const char *path,
+                                      const char *name)
+{
+       char buf[PATH_MAX];
+       struct stat st1, st2;
+       const char *final_name;
+
+       if (dmt->type == DM_DEVICE_CREATE) {
+               log_error("Name \"%s\" invalid. It contains \"/\".", path);
                return 0;
        }
 
-       if (new_name)
-               dmt->dev_name = new_name;
-       else if (!(dmt->dev_name = dm_strdup(name))) {
-               log_error("dm_task_set_name: strdup(%s) failed", name);
+       if (stat(path, &st1)) {
+               log_error("Device %s not found", path);
                return 0;
        }
 
+       /*
+        * If supplied path points to same device as last component
+        * under /dev/mapper, use that name directly.  Otherwise call
+        * _find_dm_name_of_device() to scan _dm_dir for a match.
+        */
+       if (dm_snprintf(buf, sizeof(buf), "%s/%s", _dm_dir, name) == -1) {
+               log_error("Couldn't create path for %s", name);
+               return 0;
+       }
+
+       if (!stat(buf, &st2) && (st1.st_rdev == st2.st_rdev))
+               final_name = name;
+       else if (_find_dm_name_of_device(st1.st_rdev, buf, sizeof(buf)))
+               final_name = buf;
+       else {
+               log_error("Device %s not found", name);
+               return 0;
+       }
+
+       /* This is an already existing path - do not mangle! */
+       return _dm_task_set_name(dmt, final_name, DM_STRING_MANGLING_NONE);
+}
+
+int dm_task_set_name(struct dm_task *dmt, const char *name)
+{
+       char *pos;
+
+       /* Path supplied for existing device? */
+       if ((pos = strrchr(name, '/')))
+               return _dm_task_set_name_from_path(dmt, name, pos + 1);
+
+       return _dm_task_set_name(dmt, name, dm_get_name_mangling_mode());
+}
+
+const char *dm_task_get_name(const struct dm_task *dmt)
+{
+       return (dmt->dmi.v4->name);
+}
+
+static char *_task_get_string_mangled(const char *str, const char *str_name,
+                                     char *buf, size_t buf_size,
+                                     dm_string_mangling_t mode)
+{
+       char *rs;
+       int r;
+
+       if ((r = mangle_string(str, str_name, strlen(str), buf, buf_size, mode)) < 0)
+               return NULL;
+
+       if (!(rs = r ? dm_strdup(buf) : dm_strdup(str)))
+               log_error("_task_get_string_mangled: dm_strdup failed");
+
+       return rs;
+}
+
+static char *_task_get_string_unmangled(const char *str, const char *str_name,
+                                       char *buf, size_t buf_size,
+                                       dm_string_mangling_t mode)
+{
+       char *rs;
+       int r = 0;
+
+       /*
+        * Unless the mode used is 'none', the string
+        * is *already* unmangled on ioctl return!
+        */
+       if (mode == DM_STRING_MANGLING_NONE &&
+           (r = unmangle_string(str, str_name, strlen(str), buf, buf_size, mode)) < 0)
+               return NULL;
+
+       if (!(rs = r ? dm_strdup(buf) : dm_strdup(str)))
+               log_error("_task_get_string_unmangled: dm_strdup failed");
+
+       return rs;
+}
+
+char *dm_task_get_name_mangled(const struct dm_task *dmt)
+{
+       const char *s = dm_task_get_name(dmt);
+       char buf[DM_NAME_LEN];
+       char *rs;
+
+       if (!(rs = _task_get_string_mangled(s, "name", buf, sizeof(buf), dm_get_name_mangling_mode())))
+               log_error("Failed to mangle device name \"%s\".", s);
+
+       return rs;
+}
+
+char *dm_task_get_name_unmangled(const struct dm_task *dmt)
+{
+       const char *s = dm_task_get_name(dmt);
+       char buf[DM_NAME_LEN];
+       char *rs;
+
+       if (!(rs = _task_get_string_unmangled(s, "name", buf, sizeof(buf), dm_get_name_mangling_mode())))
+               log_error("Failed to unmangle device name \"%s\".", s);
+
+       return rs;
+}
+
+const char *dm_task_get_uuid(const struct dm_task *dmt)
+{
+       return (dmt->dmi.v4->uuid);
+}
+
+char *dm_task_get_uuid_mangled(const struct dm_task *dmt)
+{
+       const char *s = dm_task_get_uuid(dmt);
+       char buf[DM_UUID_LEN];
+       char *rs;
+
+       if (!(rs = _task_get_string_mangled(s, "UUID", buf, sizeof(buf), dm_get_name_mangling_mode())))
+               log_error("Failed to mangle device uuid \"%s\".", s);
+
+       return rs;
+}
+
+char *dm_task_get_uuid_unmangled(const struct dm_task *dmt)
+{
+       const char *s = dm_task_get_uuid(dmt);
+       char buf[DM_UUID_LEN];
+       char *rs;
+
+       if (!(rs = _task_get_string_unmangled(s, "UUID", buf, sizeof(buf), dm_get_name_mangling_mode())))
+               log_error("Failed to unmangle device uuid \"%s\".", s);
+
+       return rs;
+}
+
+int dm_task_set_newname(struct dm_task *dmt, const char *newname)
+{
+       dm_string_mangling_t mangling_mode = dm_get_name_mangling_mode();
+       char mangled_name[DM_NAME_LEN];
+       int r = 0;
+
+       if (strchr(newname, '/')) {
+               log_error("Name \"%s\" invalid. It contains \"/\".", newname);
+               return 0;
+       }
+
+       if (strlen(newname) >= DM_NAME_LEN) {
+               log_error("Name \"%s\" too long", newname);
+               return 0;
+       }
+
+       if (!check_multiple_mangled_string_allowed(newname, "new name", mangling_mode))
+               return_0;
+
+       if (mangling_mode != DM_STRING_MANGLING_NONE &&
+           (r = mangle_string(newname, "new name", strlen(newname), mangled_name,
+                              sizeof(mangled_name), mangling_mode)) < 0) {
+               log_error("Failed to mangle new device name \"%s\"", newname);
+               return 0;
+       }
+
+       if (r) {
+               log_debug("New device name mangled [%s]: %s --> %s",
+                         mangling_mode == DM_STRING_MANGLING_AUTO ? "auto" : "hex",
+                         newname, mangled_name);
+               newname = mangled_name;
+       }
+
+       if (!(dmt->newname = dm_strdup(newname))) {
+               log_error("dm_task_set_newname: strdup(%s) failed", newname);
+               return 0;
+       }
+
+       dmt->new_uuid = 0;
+
        return 1;
 }
 
 int dm_task_set_uuid(struct dm_task *dmt, const char *uuid)
 {
+       char mangled_uuid[DM_UUID_LEN];
+       dm_string_mangling_t mangling_mode = dm_get_name_mangling_mode();
+       int r = 0;
+
        dm_free(dmt->uuid);
+       dmt->uuid = NULL;
+       dm_free(dmt->mangled_uuid);
+       dmt->mangled_uuid = NULL;
+
+       if (!check_multiple_mangled_string_allowed(uuid, "UUID", mangling_mode))
+               return_0;
+
+       if (mangling_mode != DM_STRING_MANGLING_NONE &&
+           (r = mangle_string(uuid, "UUID", strlen(uuid), mangled_uuid,
+                              sizeof(mangled_uuid), mangling_mode)) < 0) {
+               log_error("Failed to mangle device uuid \"%s\".", uuid);
+               return 0;
+       }
+
+       if (r) {
+               log_debug("Device uuid mangled [%s]: %s --> %s",
+                         mangling_mode == DM_STRING_MANGLING_AUTO ? "auto" : "hex",
+                         uuid, mangled_uuid);
+
+               if (!(dmt->mangled_uuid = dm_strdup(mangled_uuid))) {
+                       log_error("dm_task_set_uuid: dm_strdup(%s) failed", mangled_uuid);
+                       return 0;
+               }
+       }
 
        if (!(dmt->uuid = dm_strdup(uuid))) {
                log_error("dm_task_set_uuid: strdup(%s) failed", uuid);
@@ -369,13 +801,19 @@ int dm_task_set_mode(struct dm_task *dmt, mode_t mode)
        return 1;
 }
 
+int dm_task_enable_checks(struct dm_task *dmt)
+{
+       dmt->enable_checks = 1;
+
+       return 1;
+}
+
 int dm_task_add_target(struct dm_task *dmt, uint64_t start, uint64_t size,
                       const char *ttype, const char *params)
 {
        struct target *t = create_target(start, size, ttype, params);
-
        if (!t)
-               return 0;
+               return_0;
 
        if (!dmt->head)
                dmt->head = dmt->tail = t;
@@ -399,12 +837,14 @@ static int _selabel_lookup(const char *path, mode_t mode,
        }
 
        if (selabel_lookup(_selabel_handle, scontext, path, mode)) {
-               log_error("selabel_lookup failed: %s", strerror(errno));
+               log_debug("selabel_lookup failed for %s: %s",
+                         path, strerror(errno));
                return 0;
        }
 #else
        if (matchpathcon(path, mode, scontext)) {
-               log_error("matchpathcon failed: %s", strerror(errno));
+               log_debug("matchpathcon failed for %s: %s",
+                         path, strerror(errno));
                return 0;
        }
 #endif
@@ -473,12 +913,17 @@ void selinux_release(void)
 #endif
 }
 
+static int _warn_if_op_needed(int warn_if_udev_failed)
+{
+    return warn_if_udev_failed && dm_udev_get_sync_support() && dm_udev_get_checking();
+}
+
 static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
-                        uid_t uid, gid_t gid, mode_t mode, int check_udev)
+                        uid_t uid, gid_t gid, mode_t mode, int warn_if_udev_failed)
 {
        char path[PATH_MAX];
        struct stat info;
-       dev_t dev = MKDEV(major, minor);
+       dev_t dev = MKDEV((dev_t)major, minor);
        mode_t old_mask;
 
        _build_dev_path(path, sizeof(path), dev_name);
@@ -499,15 +944,14 @@ static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
                                  dev_name);
                        return 0;
                }
-       } else if (dm_udev_get_sync_support() && dm_udev_get_checking() &&
-                  check_udev)
+       } else if (_warn_if_op_needed(warn_if_udev_failed))
                log_warn("%s not set up by udev: Falling back to direct "
                         "node creation.", path);
 
        (void) dm_prepare_selinux_context(path, S_IFBLK);
        old_mask = umask(0);
        if (mknod(path, S_IFBLK | mode, dev) < 0) {
-               log_error("Unable to make device node for '%s'", dev_name);
+               log_error("%s: mknod for %s failed: %s", path, dev_name, strerror(errno));
                umask(old_mask);
                (void) dm_prepare_selinux_context(NULL, 0);
                return 0;
@@ -525,7 +969,7 @@ static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
        return 1;
 }
 
-static int _rm_dev_node(const char *dev_name, int check_udev)
+static int _rm_dev_node(const char *dev_name, int warn_if_udev_failed)
 {
        char path[PATH_MAX];
        struct stat info;
@@ -534,8 +978,7 @@ static int _rm_dev_node(const char *dev_name, int check_udev)
 
        if (stat(path, &info) < 0)
                return 1;
-       else if (dm_udev_get_sync_support() && dm_udev_get_checking() &&
-                check_udev)
+       else if (_warn_if_op_needed(warn_if_udev_failed))
                log_warn("Node %s was not removed by udev. "
                         "Falling back to direct node removal.", path);
 
@@ -550,7 +993,7 @@ static int _rm_dev_node(const char *dev_name, int check_udev)
 }
 
 static int _rename_dev_node(const char *old_name, const char *new_name,
-                           int check_udev)
+                           int warn_if_udev_failed)
 {
        char oldpath[PATH_MAX];
        char newpath[PATH_MAX];
@@ -565,8 +1008,7 @@ static int _rename_dev_node(const char *old_name, const char *new_name,
                                  "is already present", newpath);
                        return 0;
                }
-               else if (dm_udev_get_sync_support() && dm_udev_get_checking() &&
-                        check_udev) {
+               else if (_warn_if_op_needed(warn_if_udev_failed)) {
                        if (stat(oldpath, &info) < 0 &&
                                 errno == ENOENT)
                                /* assume udev already deleted this */
@@ -590,8 +1032,7 @@ static int _rename_dev_node(const char *old_name, const char *new_name,
                        return 0;
                }
        }
-       else if (dm_udev_get_sync_support() && dm_udev_get_checking() &&
-                check_udev)
+       else if (_warn_if_op_needed(warn_if_udev_failed))
                log_warn("The node %s should have been renamed to %s "
                         "by udev but new node is not present. "
                         "Falling back to direct node rename.",
@@ -622,12 +1063,53 @@ static int _open_dev_node(const char *dev_name)
        return fd;
 }
 
-int get_dev_node_read_ahead(const char *dev_name, uint32_t *read_ahead)
+int get_dev_node_read_ahead(const char *dev_name, uint32_t major, uint32_t minor,
+                           uint32_t *read_ahead)
 {
+       char buf[24];
+       int len;
        int r = 1;
        int fd;
        long read_ahead_long;
 
+       /*
+        * If we know the device number, use sysfs if we can.
+        * Otherwise use BLKRAGET ioctl.
+        */
+       if (*_sysfs_dir && major != 0) {
+               if (dm_snprintf(_path0, sizeof(_path0), "%sdev/block/%" PRIu32
+                               ":%" PRIu32 "/bdi/read_ahead_kb", _sysfs_dir,
+                               major, minor) < 0) {
+                       log_error("Failed to build sysfs_path.");
+                       return 0;
+               }
+
+               if ((fd = open(_path0, O_RDONLY, 0)) != -1) {
+                       /* Reading from sysfs, expecting number\n */
+                       if ((len = read(fd, buf, sizeof(buf) - 1)) < 1) {
+                               log_sys_error("read", _path0);
+                               r = 0;
+                       } else {
+                               buf[len] = 0; /* kill \n and ensure \0 */
+                               *read_ahead = atoi(buf) * 2;
+                               log_debug("%s (%d:%d): read ahead is %" PRIu32,
+                                         dev_name, major, minor, *read_ahead);
+                       }
+
+                       if (close(fd))
+                               log_sys_debug("close", _path0);
+
+                       return r;
+               }
+
+               log_sys_debug("open", _path0);
+               /* Fall back to use dev_name */
+       }
+
+       /*
+        * Open/close dev_name may block the process
+        * (i.e. overfilled thin pool volume)
+        */
        if (!*dev_name) {
                log_error("Empty device name passed to BLKRAGET");
                return 0;
@@ -640,23 +1122,64 @@ int get_dev_node_read_ahead(const char *dev_name, uint32_t *read_ahead)
                log_sys_error("BLKRAGET", dev_name);
                *read_ahead = 0;
                r = 0;
-       }  else {
+       } else {
                *read_ahead = (uint32_t) read_ahead_long;
                log_debug("%s: read ahead is %" PRIu32, dev_name, *read_ahead);
        }
 
        if (close(fd))
-               stack;
+               log_sys_debug("close", dev_name);
 
        return r;
 }
 
-static int _set_read_ahead(const char *dev_name, uint32_t read_ahead)
+static int _set_read_ahead(const char *dev_name, uint32_t major, uint32_t minor,
+                          uint32_t read_ahead)
 {
+       char buf[24];
+       int len;
        int r = 1;
        int fd;
        long read_ahead_long = (long) read_ahead;
 
+       log_debug("%s (%d:%d): Setting read ahead to %" PRIu32, dev_name,
+                 major, minor, read_ahead);
+
+       /*
+        * If we know the device number, use sysfs if we can.
+        * Otherwise use BLKRASET ioctl. RA is set after resume.
+        */
+       if (*_sysfs_dir && major != 0) {
+               if (dm_snprintf(_path0, sizeof(_path0), "%sdev/block/%" PRIu32
+                               ":%" PRIu32 "/bdi/read_ahead_kb",
+                               _sysfs_dir, major, minor) < 0) {
+                       log_error("Failed to build sysfs_path.");
+                       return 0;
+               }
+
+               /* Sysfs is kB based, round up to kB */
+               if ((len = dm_snprintf(buf, sizeof(buf), "%" PRIu32,
+                                      (read_ahead + 1) / 2)) < 0) {
+                       log_error("Failed to build size in kB.");
+                       return 0;
+               }
+
+               if ((fd = open(_path0, O_WRONLY, 0)) != -1) {
+                       if (write(fd, buf, len) < len) {
+                               log_sys_error("write", _path0);
+                               r = 0;
+                       }
+
+                       if (close(fd))
+                               log_sys_debug("close", _path0);
+
+                       return r;
+               }
+
+               log_sys_debug("open", _path0);
+               /* Fall back to use dev_name */
+       }
+
        if (!*dev_name) {
                log_error("Empty device name passed to BLKRAGET");
                return 0;
@@ -665,21 +1188,20 @@ static int _set_read_ahead(const char *dev_name, uint32_t read_ahead)
        if ((fd = _open_dev_node(dev_name)) < 0)
                return_0;
 
-       log_debug("%s: Setting read ahead to %" PRIu32, dev_name, read_ahead);
-
        if (ioctl(fd, BLKRASET, read_ahead_long)) {
                log_sys_error("BLKRASET", dev_name);
                r = 0;
        }
 
        if (close(fd))
-               stack;
+               log_sys_debug("close", dev_name);
 
        return r;
 }
 
-static int _set_dev_node_read_ahead(const char *dev_name, uint32_t read_ahead,
-                                   uint32_t read_ahead_flags)
+static int _set_dev_node_read_ahead(const char *dev_name,
+                                   uint32_t major, uint32_t minor,
+                                   uint32_t read_ahead, uint32_t read_ahead_flags)
 {
        uint32_t current_read_ahead;
 
@@ -690,7 +1212,7 @@ static int _set_dev_node_read_ahead(const char *dev_name, uint32_t read_ahead,
                read_ahead = 0;
 
        if (read_ahead_flags & DM_READ_AHEAD_MINIMUM_FLAG) {
-               if (!get_dev_node_read_ahead(dev_name, &current_read_ahead))
+               if (!get_dev_node_read_ahead(dev_name, major, minor, &current_read_ahead))
                        return_0;
 
                if (current_read_ahead > read_ahead) {
@@ -701,7 +1223,7 @@ static int _set_dev_node_read_ahead(const char *dev_name, uint32_t read_ahead,
                }
        }
 
-       return _set_read_ahead(dev_name, read_ahead);
+       return _set_read_ahead(dev_name, major, minor, read_ahead);
 }
 
 #else
@@ -713,8 +1235,9 @@ int get_dev_node_read_ahead(const char *dev_name, uint32_t *read_ahead)
        return 1;
 }
 
-static int _set_dev_node_read_ahead(const char *dev_name, uint32_t read_ahead,
-                                   uint32_t read_ahead_flags)
+static int _set_dev_node_read_ahead(const char *dev_name,
+                                   uint32_t major, uint32_t minor,
+                                   uint32_t read_ahead, uint32_t read_ahead_flags)
 {
        return 1;
 }
@@ -724,31 +1247,35 @@ typedef enum {
        NODE_ADD,
        NODE_DEL,
        NODE_RENAME,
-       NODE_READ_AHEAD
+       NODE_READ_AHEAD,
+       NUM_NODES
 } node_op_t;
 
 static int _do_node_op(node_op_t type, const char *dev_name, uint32_t major,
                       uint32_t minor, uid_t uid, gid_t gid, mode_t mode,
                       const char *old_name, uint32_t read_ahead,
-                      uint32_t read_ahead_flags, int check_udev)
+                      uint32_t read_ahead_flags, int warn_if_udev_failed)
 {
        switch (type) {
        case NODE_ADD:
                return _add_dev_node(dev_name, major, minor, uid, gid,
-                                    mode, check_udev);
+                                    mode, warn_if_udev_failed);
        case NODE_DEL:
-               return _rm_dev_node(dev_name, check_udev);
+               return _rm_dev_node(dev_name, warn_if_udev_failed);
        case NODE_RENAME:
-               return _rename_dev_node(old_name, dev_name, check_udev);
+               return _rename_dev_node(old_name, dev_name, warn_if_udev_failed);
        case NODE_READ_AHEAD:
-               return _set_dev_node_read_ahead(dev_name, read_ahead,
-                                               read_ahead_flags);
+               return _set_dev_node_read_ahead(dev_name, major, minor,
+                                               read_ahead, read_ahead_flags);
+       default:
+               ; /* NOTREACHED */
        }
 
        return 1;
 }
 
 static DM_LIST_INIT(_node_ops);
+static int _count_node_ops[NUM_NODES];
 
 struct node_op_parms {
        struct dm_list list;
@@ -762,7 +1289,8 @@ struct node_op_parms {
        uint32_t read_ahead;
        uint32_t read_ahead_flags;
        char *old_name;
-       int check_udev;
+       int warn_if_udev_failed;
+       unsigned rely_on_udev;
        char names[0];
 };
 
@@ -773,10 +1301,56 @@ static void _store_str(char **pos, char **ptr, const char *str)
        *pos += strlen(*ptr) + 1;
 }
 
+static void _del_node_op(struct node_op_parms *nop)
+{
+       _count_node_ops[nop->type]--;
+       dm_list_del(&nop->list);
+       dm_free(nop);
+
+}
+
+/* Check if there is other the type of node operation stacked */
+static int _other_node_ops(node_op_t type)
+{
+       unsigned i;
+
+       for (i = 0; i < NUM_NODES; i++)
+               if (type != i && _count_node_ops[i])
+                       return 1;
+       return 0;
+}
+
+static void _log_node_op(const char *action_str, struct node_op_parms *nop)
+{
+       const char *rely = nop->rely_on_udev ? " [trust_udev]" : "" ;
+       const char *verify = nop->warn_if_udev_failed ? " [verify_udev]" : "";
+
+       switch (nop->type) {
+       case NODE_ADD:
+               log_debug("%s: %s NODE_ADD (%" PRIu32 ",%" PRIu32 ") %u:%u 0%o%s%s",
+                         nop->dev_name, action_str, nop->major, nop->minor, nop->uid, nop->gid, nop->mode,
+                         rely, verify);
+               break;
+       case NODE_DEL:
+               log_debug("%s: %s NODE_DEL%s%s", nop->dev_name, action_str, rely, verify);
+               break;
+       case NODE_RENAME:
+               log_debug("%s: %s NODE_RENAME to %s%s%s", nop->old_name, action_str, nop->dev_name, rely, verify);
+               break;
+       case NODE_READ_AHEAD:
+               log_debug("%s: %s NODE_READ_AHEAD %" PRIu32 " (flags=%" PRIu32 ")%s%s",
+                         nop->dev_name, action_str, nop->read_ahead, nop->read_ahead_flags, rely, verify);
+               break;
+       default:
+               ; /* NOTREACHED */
+       }
+}
+
 static int _stack_node_op(node_op_t type, const char *dev_name, uint32_t major,
                          uint32_t minor, uid_t uid, gid_t gid, mode_t mode,
                          const char *old_name, uint32_t read_ahead,
-                         uint32_t read_ahead_flags, int check_udev)
+                         uint32_t read_ahead_flags, int warn_if_udev_failed,
+                         unsigned rely_on_udev)
 {
        struct node_op_parms *nop;
        struct dm_list *noph, *nopht;
@@ -784,16 +1358,55 @@ static int _stack_node_op(node_op_t type, const char *dev_name, uint32_t major,
        char *pos;
 
        /*
-        * Ignore any outstanding operations on the node if deleting it
+        * Note: warn_if_udev_failed must have valid content
         */
-       if (type == NODE_DEL) {
+       if ((type == NODE_DEL) && _other_node_ops(type))
+               /*
+                * Ignore any outstanding operations on the node if deleting it.
+                */
                dm_list_iterate_safe(noph, nopht, &_node_ops) {
                        nop = dm_list_item(noph, struct node_op_parms);
                        if (!strcmp(dev_name, nop->dev_name)) {
-                               dm_list_del(&nop->list);
-                               dm_free(nop);
+                               _log_node_op("Unstacking", nop);
+                               _del_node_op(nop);
+                               if (!_other_node_ops(type))
+                                       break; /* no other non DEL ops */
+                       }
+               }
+       else if ((type == NODE_ADD) && _count_node_ops[NODE_DEL])
+               /*
+                * Ignore previous DEL operation on added node.
+                * (No other operations for this device then DEL could be stacked here).
+                */
+               dm_list_iterate_safe(noph, nopht, &_node_ops) {
+                       nop = dm_list_item(noph, struct node_op_parms);
+                       if ((nop->type == NODE_DEL) &&
+                           !strcmp(dev_name, nop->dev_name)) {
+                               _log_node_op("Unstacking", nop);
+                               _del_node_op(nop);
+                               break; /* no other DEL ops */
                        }
                }
+       else if (type == NODE_RENAME)
+               /*
+                * Ignore any outstanding operations if renaming it.
+                *
+                * Currently  RENAME operation happens through 'suspend -> resume'.
+                * On 'resume' device is added with read_ahead settings, so it is
+                * safe to remove any stacked ADD, RENAME, READ_AHEAD operation
+                * There cannot be any DEL operation on the renamed device.
+                */
+               dm_list_iterate_safe(noph, nopht, &_node_ops) {
+                       nop = dm_list_item(noph, struct node_op_parms);
+                       if (!strcmp(old_name, nop->dev_name)) {
+                               _log_node_op("Unstacking", nop);
+                               _del_node_op(nop);
+                       }
+               }
+       else if (type == NODE_READ_AHEAD) {
+               /* udev doesn't process readahead */
+               rely_on_udev = 0;
+               warn_if_udev_failed = 0;
        }
 
        if (!(nop = dm_malloc(sizeof(*nop) + len))) {
@@ -810,13 +1423,22 @@ static int _stack_node_op(node_op_t type, const char *dev_name, uint32_t major,
        nop->mode = mode;
        nop->read_ahead = read_ahead;
        nop->read_ahead_flags = read_ahead_flags;
-       nop->check_udev = check_udev;
+       nop->rely_on_udev = rely_on_udev;
+
+       /*
+        * Clear warn_if_udev_failed if rely_on_udev is set.  It doesn't get
+        * checked in this case - this just removes the flag from log messages.
+        */
+       nop->warn_if_udev_failed = rely_on_udev ? 0 : warn_if_udev_failed;
 
        _store_str(&pos, &nop->dev_name, dev_name);
        _store_str(&pos, &nop->old_name, old_name);
 
+       _count_node_ops[type]++;
        dm_list_add(&_node_ops, &nop->list);
 
+       _log_node_op("Stacking", nop);
+
        return 1;
 }
 
@@ -827,52 +1449,46 @@ static void _pop_node_ops(void)
 
        dm_list_iterate_safe(noph, nopht, &_node_ops) {
                nop = dm_list_item(noph, struct node_op_parms);
-               _do_node_op(nop->type, nop->dev_name, nop->major, nop->minor,
-                           nop->uid, nop->gid, nop->mode, nop->old_name,
-                           nop->read_ahead, nop->read_ahead_flags,
-                           nop->check_udev);
-               dm_list_del(&nop->list);
-               dm_free(nop);
+               if (!nop->rely_on_udev) {
+                       _log_node_op("Processing", nop);
+                       _do_node_op(nop->type, nop->dev_name, nop->major, nop->minor,
+                                   nop->uid, nop->gid, nop->mode, nop->old_name,
+                                   nop->read_ahead, nop->read_ahead_flags,
+                                   nop->warn_if_udev_failed);
+               } else
+                       _log_node_op("Skipping", nop);
+               _del_node_op(nop);
        }
 }
 
 int add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
-                uid_t uid, gid_t gid, mode_t mode, int check_udev)
+                uid_t uid, gid_t gid, mode_t mode, int check_udev, unsigned rely_on_udev)
 {
-       log_debug("%s: Stacking NODE_ADD (%" PRIu32 ",%" PRIu32 ") %u:%u 0%o",
-                 dev_name, major, minor, uid, gid, mode);
-
        return _stack_node_op(NODE_ADD, dev_name, major, minor, uid,
-                             gid, mode, "", 0, 0, check_udev);
+                             gid, mode, "", 0, 0, check_udev, rely_on_udev);
 }
 
-int rename_dev_node(const char *old_name, const char *new_name, int check_udev)
+int rename_dev_node(const char *old_name, const char *new_name, int check_udev, unsigned rely_on_udev)
 {
-       log_debug("%s: Stacking NODE_RENAME to %s", old_name, new_name);
-
        return _stack_node_op(NODE_RENAME, new_name, 0, 0, 0,
-                             0, 0, old_name, 0, 0, check_udev);
+                             0, 0, old_name, 0, 0, check_udev, rely_on_udev);
 }
 
-int rm_dev_node(const char *dev_name, int check_udev)
+int rm_dev_node(const char *dev_name, int check_udev, unsigned rely_on_udev)
 {
-       log_debug("%s: Stacking NODE_DEL (replaces other stacked ops)", dev_name);
-
        return _stack_node_op(NODE_DEL, dev_name, 0, 0, 0,
-                             0, 0, "", 0, 0, check_udev);
+                             0, 0, "", 0, 0, check_udev, rely_on_udev);
 }
 
-int set_dev_node_read_ahead(const char *dev_name, uint32_t read_ahead,
-                           uint32_t read_ahead_flags)
+int set_dev_node_read_ahead(const char *dev_name,
+                            uint32_t major, uint32_t minor,
+                           uint32_t read_ahead, uint32_t read_ahead_flags)
 {
        if (read_ahead == DM_READ_AHEAD_AUTO)
                return 1;
 
-       log_debug("%s: Stacking NODE_READ_AHEAD %" PRIu32 " (flags=%" PRIu32
-                 ")", dev_name, read_ahead, read_ahead_flags);
-
-       return _stack_node_op(NODE_READ_AHEAD, dev_name, 0, 0, 0, 0,
-                              0, "", read_ahead, read_ahead_flags, 0);
+       return _stack_node_op(NODE_READ_AHEAD, dev_name, major, minor, 0, 0,
+                              0, "", read_ahead, read_ahead_flags, 0, 0);
 }
 
 void update_devs(void)
@@ -880,33 +1496,282 @@ void update_devs(void)
        _pop_node_ops();
 }
 
-int dm_set_dev_dir(const char *dev_dir)
+static int _canonicalize_and_set_dir(const char *src, const char *suffix, size_t max_len, char *dir)
 {
        size_t len;
        const char *slash;
-       if (*dev_dir != '/') {
-               log_debug("Invalid dev_dir value, %s: "
-                         "not an absolute name.", dev_dir);
+
+       if (*src != '/') {
+               log_debug("Invalid directory value, %s: "
+                         "not an absolute name.", src);
                return 0;
        }
 
-       len = strlen(dev_dir);
-       slash = dev_dir[len-1] == '/' ? "" : "/";
+       len = strlen(src);
+       slash = src[len-1] == '/' ? "" : "/";
 
-       if (snprintf(_dm_dir, sizeof _dm_dir, "%s%s%s", dev_dir, slash, DM_DIR)
-           >= sizeof _dm_dir) {
-               log_debug("Invalid dev_dir value, %s: name too long.", dev_dir);
+       if (dm_snprintf(dir, max_len, "%s%s%s", src, slash, suffix ? suffix : "") < 0) {
+               log_debug("Invalid directory value, %s: name too long.", src);
                return 0;
        }
 
        return 1;
 }
 
+int dm_set_dev_dir(const char *dev_dir)
+{
+       return _canonicalize_and_set_dir(dev_dir, DM_DIR, sizeof _dm_dir, _dm_dir);
+}
+
 const char *dm_dir(void)
 {
        return _dm_dir;
 }
 
+int dm_set_sysfs_dir(const char *sysfs_dir)
+{
+       if (!sysfs_dir || !*sysfs_dir) {
+               _sysfs_dir[0] = '\0';
+               return 1;
+       }
+       else
+               return _canonicalize_and_set_dir(sysfs_dir, NULL, sizeof _sysfs_dir, _sysfs_dir);
+}
+
+const char *dm_sysfs_dir(void)
+{
+       return _sysfs_dir;
+}
+
+/*
+ * Replace existing uuid_prefix provided it isn't too long.
+ */
+int dm_set_uuid_prefix(const char *uuid_prefix)
+{
+       if (!uuid_prefix)
+               return_0;
+
+       if (strlen(uuid_prefix) > DM_MAX_UUID_PREFIX_LEN) {
+               log_error("New uuid prefix %s too long.", uuid_prefix);
+               return 0;
+       }
+
+       strcpy(_default_uuid_prefix, uuid_prefix);
+
+       return 1;
+}
+
+const char *dm_uuid_prefix(void)
+{
+       return _default_uuid_prefix;
+}
+
+static int _sysfs_get_dm_name(uint32_t major, uint32_t minor, char *buf, size_t buf_size)
+{
+       char *sysfs_path, *temp_buf = NULL;
+       FILE *fp = NULL;
+       int r = 0;
+       size_t len;
+
+       if (!(sysfs_path = dm_malloc(PATH_MAX)) ||
+           !(temp_buf = dm_malloc(PATH_MAX))) {
+               log_error("_sysfs_get_dm_name: failed to allocate temporary buffers");
+               goto bad;
+       }
+
+       if (dm_snprintf(sysfs_path, PATH_MAX, "%sdev/block/%" PRIu32 ":%" PRIu32
+                       "/dm/name", _sysfs_dir, major, minor) < 0) {
+               log_error("_sysfs_get_dm_name: dm_snprintf failed");
+               goto bad;
+       }
+
+       if (!(fp = fopen(sysfs_path, "r"))) {
+               if (errno != ENOENT)
+                       log_sys_error("fopen", sysfs_path);
+               else
+                       log_sys_debug("fopen", sysfs_path);
+               goto bad;
+       }
+
+       if (!fgets(temp_buf, PATH_MAX, fp)) {
+               log_sys_error("fgets", sysfs_path);
+               goto bad;
+       }
+
+       len = strlen(temp_buf);
+
+       if (len > buf_size) {
+               log_error("_sysfs_get_dm_name: supplied buffer too small");
+               goto bad;
+       }
+
+       temp_buf[len ? len - 1 : 0] = '\0'; /* \n */
+       strcpy(buf, temp_buf);
+       r = 1;
+bad:
+       if (fp && fclose(fp))
+               log_sys_error("fclose", sysfs_path);
+
+       dm_free(temp_buf);
+       dm_free(sysfs_path);
+
+       return r;
+}
+
+static int _sysfs_get_kernel_name(uint32_t major, uint32_t minor, char *buf, size_t buf_size)
+{
+       char *name, *sysfs_path, *temp_buf = NULL;
+       ssize_t size;
+       size_t len;
+       int r = 0;
+
+       if (!(sysfs_path = dm_malloc(PATH_MAX)) ||
+           !(temp_buf = dm_malloc(PATH_MAX))) {
+               log_error("_sysfs_get_kernel_name: failed to allocate temporary buffers");
+               goto bad;
+       }
+
+       if (dm_snprintf(sysfs_path, PATH_MAX, "%sdev/block/%" PRIu32 ":%" PRIu32,
+                       _sysfs_dir, major, minor) < 0) {
+               log_error("_sysfs_get_kernel_name: dm_snprintf failed");
+               goto bad;
+       }
+
+       if ((size = readlink(sysfs_path, temp_buf, PATH_MAX - 1)) < 0) {
+               if (errno != ENOENT)
+                       log_sys_error("readlink", sysfs_path);
+               else
+                       log_sys_debug("readlink", sysfs_path);
+               goto bad;
+       }
+       temp_buf[size] = '\0';
+
+       if (!(name = strrchr(temp_buf, '/'))) {
+               log_error("Could not locate device kernel name in sysfs path %s", temp_buf);
+               goto bad;
+       }
+       name += 1;
+       len = size - (name - temp_buf) + 1;
+
+       if (len > buf_size) {
+               log_error("_sysfs_get_kernel_name: output buffer too small");
+               goto bad;
+       }
+
+       strcpy(buf, name);
+       r = 1;
+bad:
+       dm_free(temp_buf);
+       dm_free(sysfs_path);
+
+       return r;
+}
+
+int dm_device_get_name(uint32_t major, uint32_t minor, int prefer_kernel_name,
+                      char *buf, size_t buf_size)
+{
+       if (!*_sysfs_dir)
+               return 0;
+
+       /*
+        * device-mapper devices and prefer_kernel_name = 0
+        * get dm name by reading /sys/dev/block/major:minor/dm/name,
+        * fallback to _sysfs_get_kernel_name if not successful
+        */
+       if (dm_is_dm_major(major) && !prefer_kernel_name) {
+               if (_sysfs_get_dm_name(major, minor, buf, buf_size))
+                       return 1;
+               else
+                       stack;
+       }
+
+       /*
+        * non-device-mapper devices or prefer_kernel_name = 1
+        * get kernel name using readlink /sys/dev/block/major:minor -> .../dm-X
+        */
+       return _sysfs_get_kernel_name(major, minor, buf, buf_size);
+}
+
+int dm_device_has_holders(uint32_t major, uint32_t minor)
+{
+       char sysfs_path[PATH_MAX];
+       struct stat st;
+
+       if (!*_sysfs_dir)
+               return 0;
+
+       if (dm_snprintf(sysfs_path, PATH_MAX, "%sdev/block/%" PRIu32
+                       ":%" PRIu32 "/holders", _sysfs_dir, major, minor) < 0) {
+               log_error("sysfs_path dm_snprintf failed");
+               return 0;
+       }
+
+       if (stat(sysfs_path, &st)) {
+               log_sys_error("stat", sysfs_path);
+               return 0;
+       }
+
+       return !dm_is_empty_dir(sysfs_path);
+}
+
+static int _mounted_fs_on_device(const char *kernel_dev_name)
+{
+       char sysfs_path[PATH_MAX];
+       struct dirent *dirent;
+       DIR *d;
+       struct stat st;
+       int r = 0;
+
+       if (dm_snprintf(sysfs_path, PATH_MAX, "%sfs", _sysfs_dir) < 0) {
+               log_error("sysfs_path dm_snprintf failed");
+               return 0;
+       }
+
+       if (!(d = opendir(sysfs_path))) {
+               if (errno != ENOENT)
+                       log_sys_error("opendir", sysfs_path);
+               return 0;
+       }
+
+       while ((dirent = readdir(d))) {
+               if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, ".."))
+                       continue;
+
+               if (dm_snprintf(sysfs_path, PATH_MAX, "%sfs/%s/%s",
+                               _sysfs_dir, dirent->d_name, kernel_dev_name) < 0) {
+                       log_error("sysfs_path dm_snprintf failed");
+                       break;
+               }
+
+               if (!stat(sysfs_path, &st)) {
+                       /* found! */
+                       r = 1;
+                       break;
+               }
+               else if (errno != ENOENT) {
+                       log_sys_error("stat", sysfs_path);
+                       break;
+               }
+       }
+
+       if (closedir(d))
+               log_error("_fs_present_on_device: %s: closedir failed", kernel_dev_name);
+
+       return r;
+}
+
+int dm_device_has_mounted_fs(uint32_t major, uint32_t minor)
+{
+       char kernel_dev_name[PATH_MAX];
+
+       /* Get kernel device name first */
+       if (!dm_device_get_name(major, minor, 1, kernel_dev_name, PATH_MAX))
+               return 0;
+
+       /* Check /sys/fs/<fs_name>/<kernel_dev_name> presence */
+       return _mounted_fs_on_device(kernel_dev_name);
+}
+
 int dm_mknodes(const char *name)
 {
        struct dm_task *dmt;
@@ -984,6 +1849,8 @@ int dm_udev_complete(uint32_t cookie)
 
 int dm_udev_wait(uint32_t cookie)
 {
+       update_devs();
+
        return 1;
 }
 
@@ -1111,6 +1978,7 @@ static int _get_cookie_sem(uint32_t cookie, int *semid)
 static int _udev_notify_sem_inc(uint32_t cookie, int semid)
 {
        struct sembuf sb = {0, 1, 0};
+       int val;
 
        if (semop(semid, &sb, 1) < 0) {
                log_error("semid %d: semop failed for cookie 0x%" PRIx32 ": %s",
@@ -1118,8 +1986,15 @@ static int _udev_notify_sem_inc(uint32_t cookie, int semid)
                return 0;
        }
 
-       log_debug("Udev cookie 0x%" PRIx32 " (semid %d) incremented",
-                 cookie, semid);
+       if ((val = semctl(semid, 0, GETVAL)) < 0) {
+               log_error("semid %d: sem_ctl GETVAL failed for "
+                         "cookie 0x%" PRIx32 ": %s",
+                         semid, cookie, strerror(errno));
+               return 0;               
+       }
+
+       log_debug("Udev cookie 0x%" PRIx32 " (semid %d) incremented to %d",
+                 cookie, semid, val);
 
        return 1;
 }
@@ -1127,6 +2002,14 @@ static int _udev_notify_sem_inc(uint32_t cookie, int semid)
 static int _udev_notify_sem_dec(uint32_t cookie, int semid)
 {
        struct sembuf sb = {0, -1, IPC_NOWAIT};
+       int val;
+
+       if ((val = semctl(semid, 0, GETVAL)) < 0) {
+               log_error("semid %d: sem_ctl GETVAL failed for "
+                         "cookie 0x%" PRIx32 ": %s",
+                         semid, cookie, strerror(errno));
+               return 0;
+       }
 
        if (semop(semid, &sb, 1) < 0) {
                switch (errno) {
@@ -1145,8 +2028,8 @@ static int _udev_notify_sem_dec(uint32_t cookie, int semid)
                return 0;
        }
 
-       log_debug("Udev cookie 0x%" PRIx32 " (semid %d) decremented",
-                 cookie, semid);
+       log_debug("Udev cookie 0x%" PRIx32 " (semid %d) decremented to %d",
+                 cookie, semid, val - 1);
 
        return 1;
 }
@@ -1170,6 +2053,7 @@ static int _udev_notify_sem_create(uint32_t *cookie, int *semid)
 {
        int fd;
        int gen_semid;
+       int val;
        uint16_t base_cookie;
        uint32_t gen_cookie;
        union semun sem_arg;
@@ -1230,8 +2114,15 @@ static int _udev_notify_sem_create(uint32_t *cookie, int *semid)
                goto bad;
        }
 
-       log_debug("Udev cookie 0x%" PRIx32 " (semid %d) incremented",
-                 gen_cookie, gen_semid);
+       if ((val = semctl(gen_semid, 0, GETVAL)) < 0) {
+               log_error("semid %d: sem_ctl GETVAL failed for "
+                         "cookie 0x%" PRIx32 ": %s",
+                         gen_semid, gen_cookie, strerror(errno));
+               goto bad;
+       }
+
+       log_debug("Udev cookie 0x%" PRIx32 " (semid %d) incremented to %d",
+                 gen_cookie, gen_semid, val);
 
        if (close(fd))
                stack;
@@ -1262,6 +2153,51 @@ int dm_udev_create_cookie(uint32_t *cookie)
        return _udev_notify_sem_create(cookie, &semid);
 }
 
+static const char *_task_type_disp(int type)
+{
+       switch(type) {
+       case DM_DEVICE_CREATE:
+               return "CREATE";
+        case DM_DEVICE_RELOAD:
+               return "RELOAD";
+        case DM_DEVICE_REMOVE:
+               return "REMOVE";
+        case DM_DEVICE_REMOVE_ALL:
+               return "REMOVE_ALL";
+        case DM_DEVICE_SUSPEND:
+               return "SUSPEND";
+        case DM_DEVICE_RESUME:
+               return "RESUME";
+        case DM_DEVICE_INFO:
+               return "INFO";
+        case DM_DEVICE_DEPS:
+               return "DEPS";
+        case DM_DEVICE_RENAME:
+               return "RENAME";
+        case DM_DEVICE_VERSION:
+               return "VERSION";
+        case DM_DEVICE_STATUS:
+               return "STATUS";
+        case DM_DEVICE_TABLE:
+               return "TABLE";
+        case DM_DEVICE_WAITEVENT:
+               return "WAITEVENT";
+        case DM_DEVICE_LIST:
+               return "LIST";
+        case DM_DEVICE_CLEAR:
+               return "CLEAR";
+        case DM_DEVICE_MKNODES:
+               return "MKNODES";
+        case DM_DEVICE_LIST_VERSIONS:
+               return "LIST_VERSIONS";
+        case DM_DEVICE_TARGET_MSG:
+               return "TARGET_MSG";
+        case DM_DEVICE_SET_GEOMETRY:
+               return "SET_GEOMETRY";
+       }
+       return "unknown";
+}
+
 int dm_task_set_cookie(struct dm_task *dmt, uint32_t *cookie, uint16_t flags)
 {
        int semid;
@@ -1290,8 +2226,16 @@ int dm_task_set_cookie(struct dm_task *dmt, uint32_t *cookie, uint16_t flags)
        dmt->event_nr |= ~DM_UDEV_FLAGS_MASK & *cookie;
        dmt->cookie_set = 1;
 
-       log_debug("Udev cookie 0x%" PRIx32 " (semid %d) assigned to dm_task "
-                 "type %d with flags 0x%" PRIx16, *cookie, semid, dmt->type, flags);
+       log_debug("Udev cookie 0x%" PRIx32 " (semid %d) assigned to "
+                 "%s task(%d) with flags%s%s%s%s%s%s%s (0x%" PRIx16 ")", *cookie, semid, _task_type_disp(dmt->type), dmt->type, 
+                 (flags & DM_UDEV_DISABLE_DM_RULES_FLAG) ? " DISABLE_DM_RULES" : "",
+                 (flags & DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG) ? " DISABLE_SUBSYSTEM_RULES" : "",
+                 (flags & DM_UDEV_DISABLE_DISK_RULES_FLAG) ? " DISABLE_DISK_RULES" : "",
+                 (flags & DM_UDEV_DISABLE_OTHER_RULES_FLAG) ? " DISABLE_OTHER_RULES" : "",
+                 (flags & DM_UDEV_LOW_PRIORITY_FLAG) ? " LOW_PRIORITY" : "",
+                 (flags & DM_UDEV_DISABLE_LIBRARY_FALLBACK) ? " DISABLE_LIBRARY_FALLBACK" : "",
+                 (flags & DM_UDEV_PRIMARY_SOURCE_FLAG) ? " PRIMARY_SOURCE" : "",
+                 flags);
 
        return 1;
 
@@ -1320,7 +2264,7 @@ int dm_udev_complete(uint32_t cookie)
        return 1;
 }
 
-int dm_udev_wait(uint32_t cookie)
+static int _udev_wait(uint32_t cookie)
 {
        int semid;
        struct sembuf sb = {0, 0, 0};
@@ -1340,7 +2284,7 @@ int dm_udev_wait(uint32_t cookie)
                return 0;
        }
 
-       log_debug("Udev cookie 0x%" PRIx32 " (semid %d): Waiting for zero",
+       log_debug("Udev cookie 0x%" PRIx32 " (semid %d) waiting for zero",
                  cookie, semid);
 
 repeat_wait:
@@ -1360,4 +2304,13 @@ repeat_wait:
        return _udev_notify_sem_destroy(cookie, semid);
 }
 
+int dm_udev_wait(uint32_t cookie)
+{
+       int r = _udev_wait(cookie);
+
+       update_devs();
+
+       return r;
+}
+
 #endif         /* UDEV_SYNC_SUPPORT */
index 3267cfc496dc80ccb83a8ee1a30bf1e58a85da37..4705a77ccb817a046c8b0ddb2c1c9d30e3958f70 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of the device-mapper userspace tools.
  *
 
 #include "libdevmapper.h"
 
+#define DM_DEFAULT_NAME_MANGLING_MODE_ENV_VAR_NAME "DM_DEFAULT_NAME_MANGLING_MODE"
+
+#define DEV_NAME(dmt) (dmt->mangled_dev_name ? : dmt->dev_name)
+#define DEV_UUID(DMT) (dmt->mangled_uuid ? : dmt->uuid)
+
+int mangle_string(const char *str, const char *str_name, size_t len,
+                 char *buf, size_t buf_len, dm_string_mangling_t mode);
+
+int unmangle_string(const char *str, const char *str_name, size_t len,
+                   char *buf, size_t buf_len, dm_string_mangling_t mode);
+
+int check_multiple_mangled_string_allowed(const char *str, const char *str_name,
+                                         dm_string_mangling_t mode);
+
 struct target *create_target(uint64_t start,
                             uint64_t len,
                             const char *type, const char *params);
 
 int add_dev_node(const char *dev_name, uint32_t minor, uint32_t major,
-                uid_t uid, gid_t gid, mode_t mode, int check_udev);
-int rm_dev_node(const char *dev_name, int check_udev);
+                uid_t uid, gid_t gid, mode_t mode, int check_udev, unsigned rely_on_udev);
+int rm_dev_node(const char *dev_name, int check_udev, unsigned rely_on_udev);
 int rename_dev_node(const char *old_name, const char *new_name,
-                   int check_udev);
-int get_dev_node_read_ahead(const char *dev_name, uint32_t *read_ahead);
-int set_dev_node_read_ahead(const char *dev_name, uint32_t read_ahead,
-                           uint32_t read_ahead_flags);
+                   int check_udev, unsigned rely_on_udev);
+int get_dev_node_read_ahead(const char *dev_name, uint32_t major, uint32_t minor,
+                           uint32_t *read_ahead);
+int set_dev_node_read_ahead(const char *dev_name, uint32_t major, uint32_t minor,
+                           uint32_t read_ahead, uint32_t read_ahead_flags);
 void update_devs(void);
 void selinux_release(void);
 
+void inc_suspended(void);
+void dec_suspended(void);
+
 #endif
diff --git a/libdm/libdm-config.c b/libdm/libdm-config.c
new file mode 100644 (file)
index 0000000..c19f51d
--- /dev/null
@@ -0,0 +1,1186 @@
+/*
+ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "dmlib.h"
+
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#define SECTION_B_CHAR '{'
+#define SECTION_E_CHAR '}'
+
+enum {
+       TOK_INT,
+       TOK_FLOAT,
+       TOK_STRING,             /* Single quotes */
+       TOK_STRING_ESCAPED,     /* Double quotes */
+       TOK_EQ,
+       TOK_SECTION_B,
+       TOK_SECTION_E,
+       TOK_ARRAY_B,
+       TOK_ARRAY_E,
+       TOK_IDENTIFIER,
+       TOK_COMMA,
+       TOK_EOF
+};
+
+struct parser {
+       const char *fb, *fe;            /* file limits */
+
+       int t;                  /* token limits and type */
+       const char *tb, *te;
+
+       int line;               /* line number we are on */
+
+       struct dm_pool *mem;
+};
+
+struct output_line {
+       struct dm_pool *mem;
+       dm_putline_fn putline;
+       void *putline_baton;
+};
+
+static void _get_token(struct parser *p, int tok_prev);
+static void _eat_space(struct parser *p);
+static struct dm_config_node *_file(struct parser *p);
+static struct dm_config_node *_section(struct parser *p);
+static struct dm_config_value *_value(struct parser *p);
+static struct dm_config_value *_type(struct parser *p);
+static int _match_aux(struct parser *p, int t);
+static struct dm_config_value *_create_value(struct dm_pool *mem);
+static struct dm_config_node *_create_node(struct dm_pool *mem);
+static char *_dup_tok(struct parser *p);
+
+static const int sep = '/';
+
+#define MAX_INDENT 32
+
+#define match(t) do {\
+   if (!_match_aux(p, (t))) {\
+       log_error("Parse error at byte %" PRIptrdiff_t " (line %d): unexpected token", \
+                 p->tb - p->fb + 1, p->line); \
+      return 0;\
+   } \
+} while(0)
+
+static int _tok_match(const char *str, const char *b, const char *e)
+{
+       while (*str && (b != e)) {
+               if (*str++ != *b++)
+                       return 0;
+       }
+
+       return !(*str || (b != e));
+}
+
+struct dm_config_tree *dm_config_create(void)
+{
+       struct dm_config_tree *cft;
+       struct dm_pool *mem = dm_pool_create("config", 10 * 1024);
+
+       if (!mem) {
+               log_error("Failed to allocate config pool.");
+               return 0;
+       }
+
+       if (!(cft = dm_pool_zalloc(mem, sizeof(*cft)))) {
+               log_error("Failed to allocate config tree.");
+               dm_pool_destroy(mem);
+               return 0;
+       }
+       cft->root = NULL;
+       cft->cascade = NULL;
+       cft->custom = NULL;
+       cft->mem = mem;
+       return cft;
+}
+
+void dm_config_set_custom(struct dm_config_tree *cft, void *custom)
+{
+       cft->custom = custom;
+}
+
+void *dm_config_get_custom(struct dm_config_tree *cft)
+{
+       return cft->custom;
+}
+
+void dm_config_destroy(struct dm_config_tree *cft)
+{
+       dm_pool_destroy(cft->mem);
+}
+
+/*
+ * If there's a cascaded dm_config_tree, remove and return it, otherwise
+ * return NULL.
+ */
+struct dm_config_tree *dm_config_remove_cascaded_tree(struct dm_config_tree *cft)
+{
+       struct dm_config_tree *second_cft;
+
+       if (!cft)
+               return NULL;
+
+       second_cft = cft->cascade;
+       cft->cascade = NULL;
+
+       return second_cft;
+}
+
+/*
+ * When searching, first_cft is checked before second_cft.
+ */
+struct dm_config_tree *dm_config_insert_cascaded_tree(struct dm_config_tree *first_cft, struct dm_config_tree *second_cft)
+{
+       first_cft->cascade = second_cft;
+
+       return first_cft;
+}
+
+int dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end)
+{
+       /* TODO? if (start == end) return 1; */
+
+       struct parser *p;
+       if (!(p = dm_pool_alloc(cft->mem, sizeof(*p))))
+               return_0;
+
+       p->mem = cft->mem;
+       p->fb = start;
+       p->fe = end;
+       p->tb = p->te = p->fb;
+       p->line = 1;
+
+       _get_token(p, TOK_SECTION_E);
+       if (!(cft->root = _file(p)))
+               return_0;
+
+       return 1;
+}
+
+struct dm_config_tree *dm_config_from_string(const char *config_settings)
+{
+       struct dm_config_tree *cft;
+
+       if (!(cft = dm_config_create()))
+               return_NULL;
+
+       if (!dm_config_parse(cft, config_settings, config_settings + strlen(config_settings))) {
+               dm_config_destroy(cft);
+               return_NULL;
+       }
+
+       return cft;
+}
+
+static int _line_start(struct output_line *outline)
+{
+       if (!dm_pool_begin_object(outline->mem, 128)) {
+               log_error("dm_pool_begin_object failed for config line");
+               return 0;
+       }
+
+       return 1;
+}
+
+__attribute__ ((format(printf, 2, 3)))
+static int _line_append(struct output_line *outline, const char *fmt, ...)
+{
+       char buf[4096];
+       va_list ap;
+       int n;
+
+       va_start(ap, fmt);
+       n = vsnprintf(&buf[0], sizeof buf - 1, fmt, ap);
+       va_end(ap);
+
+       if (n < 0 || n > (int) sizeof buf - 1) {
+               log_error("vsnprintf failed for config line");
+               return 0;
+       }
+
+       if (!dm_pool_grow_object(outline->mem, &buf[0], strlen(buf))) {
+               log_error("dm_pool_grow_object failed for config line");
+               return 0;
+       }
+
+       return 1;
+}
+
+#define line_append(args...) do {if (!_line_append(outline, args)) {return_0;}} while (0)
+
+static int _line_end(struct output_line *outline)
+{
+       const char *line;
+
+       if (!dm_pool_grow_object(outline->mem, "\0", 1)) {
+               log_error("dm_pool_grow_object failed for config line");
+               return 0;
+       }
+
+       line = dm_pool_end_object(outline->mem);
+
+       if (!outline->putline)
+               return 0;
+
+       outline->putline(line, outline->putline_baton);
+
+       return 1;
+}
+
+static int _write_value(struct output_line *outline, const struct dm_config_value *v)
+{
+       char *buf;
+
+       switch (v->type) {
+       case DM_CFG_STRING:
+               if (!(buf = alloca(dm_escaped_len(v->v.str)))) {
+                       log_error("temporary stack allocation for a config "
+                                 "string failed");
+                       return 0;
+               }
+               line_append("\"%s\"", dm_escape_double_quotes(buf, v->v.str));
+               break;
+
+       case DM_CFG_FLOAT:
+               line_append("%f", v->v.f);
+               break;
+
+       case DM_CFG_INT:
+               line_append("%" PRId64, v->v.i);
+               break;
+
+       case DM_CFG_EMPTY_ARRAY:
+               line_append("[]");
+               break;
+
+       default:
+               log_error("_write_value: Unknown value type: %d", v->type);
+
+       }
+
+       return 1;
+}
+
+static int _write_config(const struct dm_config_node *n, int only_one,
+                        struct output_line *outline, int level)
+{
+       char space[MAX_INDENT + 1];
+       int l = (level < MAX_INDENT) ? level : MAX_INDENT;
+       int i;
+
+       if (!n)
+               return 1;
+
+       for (i = 0; i < l; i++)
+               space[i] = '\t';
+       space[i] = '\0';
+
+       do {
+               if (!_line_start(outline))
+                       return_0;
+               line_append("%s%s", space, n->key);
+               if (!n->v) {
+                       /* it's a sub section */
+                       line_append(" {");
+                       if (!_line_end(outline))
+                               return_0;
+                       _write_config(n->child, 0, outline, level + 1);
+                       if (!_line_start(outline))
+                               return_0;
+                       line_append("%s}", space);
+               } else {
+                       /* it's a value */
+                       const struct dm_config_value *v = n->v;
+                       line_append("=");
+                       if (v->next) {
+                               line_append("[");
+                               while (v && v->type != DM_CFG_EMPTY_ARRAY) {
+                                       if (!_write_value(outline, v))
+                                               return_0;
+                                       v = v->next;
+                                       if (v && v->type != DM_CFG_EMPTY_ARRAY)
+                                               line_append(", ");
+                               }
+                               line_append("]");
+                       } else
+                               if (!_write_value(outline, v))
+                                       return_0;
+               }
+               if (!_line_end(outline))
+                       return_0;
+               n = n->sib;
+       } while (n && !only_one);
+       /* FIXME: add error checking */
+       return 1;
+}
+
+static int _write_node(const struct dm_config_node *cn, int only_one,
+                      dm_putline_fn putline, void *baton)
+{
+       struct output_line outline;
+       if (!(outline.mem = dm_pool_create("config_line", 1024)))
+               return_0;
+       outline.putline = putline;
+       outline.putline_baton = baton;
+       if (!_write_config(cn, only_one, &outline, 0)) {
+               dm_pool_destroy(outline.mem);
+               return_0;
+       }
+       dm_pool_destroy(outline.mem);
+       return 1;
+}
+
+int dm_config_write_one_node(const struct dm_config_node *cn, dm_putline_fn putline, void *baton)
+{
+       return _write_node(cn, 1, putline, baton);
+}
+
+int dm_config_write_node(const struct dm_config_node *cn, dm_putline_fn putline, void *baton)
+{
+       return _write_node(cn, 0, putline, baton);
+}
+
+/*
+ * parser
+ */
+static struct dm_config_node *_file(struct parser *p)
+{
+       struct dm_config_node *root = NULL, *n, *l = NULL;
+       while (p->t != TOK_EOF) {
+               if (!(n = _section(p)))
+                       return_NULL;
+
+               if (!root)
+                       root = n;
+               else
+                       l->sib = n;
+               n->parent = root;
+               l = n;
+       }
+       return root;
+}
+
+static struct dm_config_node *_section(struct parser *p)
+{
+       /* IDENTIFIER SECTION_B_CHAR VALUE* SECTION_E_CHAR */
+       struct dm_config_node *root, *n, *l = NULL;
+       if (!(root = _create_node(p->mem))) {
+               log_error("Failed to allocate section node");
+               return NULL;
+       }
+
+       if (!(root->key = _dup_tok(p)))
+               return_NULL;
+
+       match(TOK_IDENTIFIER);
+
+       if (p->t == TOK_SECTION_B) {
+               match(TOK_SECTION_B);
+               while (p->t != TOK_SECTION_E) {
+                       if (!(n = _section(p)))
+                               return_NULL;
+
+                       if (!l)
+                               root->child = n;
+                       else
+                               l->sib = n;
+                       n->parent = root;
+                       l = n;
+               }
+               match(TOK_SECTION_E);
+       } else {
+               match(TOK_EQ);
+               if (!(root->v = _value(p)))
+                       return_NULL;
+       }
+
+       return root;
+}
+
+static struct dm_config_value *_value(struct parser *p)
+{
+       /* '[' TYPE* ']' | TYPE */
+       struct dm_config_value *h = NULL, *l, *ll = NULL;
+       if (p->t == TOK_ARRAY_B) {
+               match(TOK_ARRAY_B);
+               while (p->t != TOK_ARRAY_E) {
+                       if (!(l = _type(p)))
+                               return_NULL;
+
+                       if (!h)
+                               h = l;
+                       else
+                               ll->next = l;
+                       ll = l;
+
+                       if (p->t == TOK_COMMA)
+                               match(TOK_COMMA);
+               }
+               match(TOK_ARRAY_E);
+               /*
+                * Special case for an empty array.
+                */
+               if (!h) {
+                       if (!(h = _create_value(p->mem))) {
+                               log_error("Failed to allocate value");
+                               return NULL;
+                       }
+
+                       h->type = DM_CFG_EMPTY_ARRAY;
+               }
+
+       } else
+               if (!(h = _type(p)))
+                       return_NULL;
+
+       return h;
+}
+
+static struct dm_config_value *_type(struct parser *p)
+{
+       /* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */
+       struct dm_config_value *v = _create_value(p->mem);
+       char *str;
+
+       if (!v) {
+               log_error("Failed to allocate type value");
+               return NULL;
+       }
+
+       switch (p->t) {
+       case TOK_INT:
+               v->type = DM_CFG_INT;
+               v->v.i = strtoll(p->tb, NULL, 0);       /* FIXME: check error */
+               match(TOK_INT);
+               break;
+
+       case TOK_FLOAT:
+               v->type = DM_CFG_FLOAT;
+               v->v.f = strtod(p->tb, NULL);   /* FIXME: check error */
+               match(TOK_FLOAT);
+               break;
+
+       case TOK_STRING:
+               v->type = DM_CFG_STRING;
+
+               p->tb++, p->te--;       /* strip "'s */
+               if (!(v->v.str = _dup_tok(p)))
+                       return_NULL;
+               p->te++;
+               match(TOK_STRING);
+               break;
+
+       case TOK_STRING_ESCAPED:
+               v->type = DM_CFG_STRING;
+
+               p->tb++, p->te--;       /* strip "'s */
+               if (!(str = _dup_tok(p)))
+                       return_NULL;
+               dm_unescape_double_quotes(str);
+               v->v.str = str;
+               p->te++;
+               match(TOK_STRING_ESCAPED);
+               break;
+
+       default:
+               log_error("Parse error at byte %" PRIptrdiff_t " (line %d): expected a value",
+                         p->tb - p->fb + 1, p->line);
+               return NULL;
+       }
+       return v;
+}
+
+static int _match_aux(struct parser *p, int t)
+{
+       if (p->t != t)
+               return 0;
+
+       _get_token(p, t);
+       return 1;
+}
+
+/*
+ * tokeniser
+ */
+static void _get_token(struct parser *p, int tok_prev)
+{
+       int values_allowed = 0;
+
+       const char *te;
+
+       p->tb = p->te;
+       _eat_space(p);
+       if (p->tb == p->fe || !*p->tb) {
+               p->t = TOK_EOF;
+               return;
+       }
+
+       /* Should next token be interpreted as value instead of identifier? */
+       if (tok_prev == TOK_EQ || tok_prev == TOK_ARRAY_B ||
+           tok_prev == TOK_COMMA)
+               values_allowed = 1;
+
+       p->t = TOK_INT;         /* fudge so the fall through for
+                                  floats works */
+
+       te = p->te;
+       switch (*te) {
+       case SECTION_B_CHAR:
+               p->t = TOK_SECTION_B;
+               te++;
+               break;
+
+       case SECTION_E_CHAR:
+               p->t = TOK_SECTION_E;
+               te++;
+               break;
+
+       case '[':
+               p->t = TOK_ARRAY_B;
+               te++;
+               break;
+
+       case ']':
+               p->t = TOK_ARRAY_E;
+               te++;
+               break;
+
+       case ',':
+               p->t = TOK_COMMA;
+               te++;
+               break;
+
+       case '=':
+               p->t = TOK_EQ;
+               te++;
+               break;
+
+       case '"':
+               p->t = TOK_STRING_ESCAPED;
+               te++;
+               while ((te != p->fe) && (*te) && (*te != '"')) {
+                       if ((*te == '\\') && (te + 1 != p->fe) &&
+                           *(te + 1))
+                               te++;
+                       te++;
+               }
+
+               if ((te != p->fe) && (*te))
+                       te++;
+               break;
+
+       case '\'':
+               p->t = TOK_STRING;
+               te++;
+               while ((te != p->fe) && (*te) && (*te != '\''))
+                       te++;
+
+               if ((te != p->fe) && (*te))
+                       te++;
+               break;
+
+       case '.':
+               p->t = TOK_FLOAT;
+               /* Fall through */
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+       case '+':
+       case '-':
+               if (values_allowed) {
+                       while (++te != p->fe) {
+                               if (!isdigit((int) *te)) {
+                                       if (*te == '.') {
+                                               if (p->t != TOK_FLOAT) {
+                                                       p->t = TOK_FLOAT;
+                                                       continue;
+                                               }
+                                       }
+                                       break;
+                               }
+                       }
+                       break;
+               }
+               /* fall through */
+
+       default:
+               p->t = TOK_IDENTIFIER;
+               while ((te != p->fe) && (*te) && !isspace(*te) &&
+                      (*te != '#') && (*te != '=') &&
+                      (*te != SECTION_B_CHAR) &&
+                      (*te != SECTION_E_CHAR))
+                       te++;
+               break;
+       }
+
+       p->te = te;
+}
+
+static void _eat_space(struct parser *p)
+{
+       while (p->tb != p->fe) {
+               if (*p->te == '#')
+                       while ((p->te != p->fe) && (*p->te != '\n') && (*p->te))
+                               ++p->te;
+
+               else if (!isspace(*p->te))
+                       break;
+
+               while ((p->te != p->fe) && isspace(*p->te)) {
+                       if (*p->te == '\n')
+                               ++p->line;
+                       ++p->te;
+               }
+
+               p->tb = p->te;
+       }
+}
+
+/*
+ * memory management
+ */
+static struct dm_config_value *_create_value(struct dm_pool *mem)
+{
+       return dm_pool_zalloc(mem, sizeof(struct dm_config_value));
+}
+
+static struct dm_config_node *_create_node(struct dm_pool *mem)
+{
+       return dm_pool_zalloc(mem, sizeof(struct dm_config_node));
+}
+
+static char *_dup_tok(struct parser *p)
+{
+       size_t len = p->te - p->tb;
+       char *str = dm_pool_alloc(p->mem, len + 1);
+       if (!str) {
+               log_error("Failed to duplicate token.");
+               return 0;
+       }
+       memcpy(str, p->tb, len);
+       str[len] = '\0';
+       return str;
+}
+
+/*
+ * Utility functions
+ */
+
+/*
+ * node_lookup_fn is either:
+ *   _find_config_node to perform a lookup starting from a given config_node 
+ *   in a config_tree;
+ * or
+ *   _find_first_config_node to find the first config_node in a set of 
+ *   cascaded trees.
+ */
+typedef const struct dm_config_node *node_lookup_fn(const void *start, const char *path);
+
+static const struct dm_config_node *_find_config_node(const void *start,
+                                                     const char *path)
+{
+       const char *e;
+       const struct dm_config_node *cn = start;
+       const struct dm_config_node *cn_found = NULL;
+
+       while (cn) {
+               /* trim any leading slashes */
+               while (*path && (*path == sep))
+                       path++;
+
+               /* find the end of this segment */
+               for (e = path; *e && (*e != sep); e++) ;
+
+               /* hunt for the node */
+               cn_found = NULL;
+               while (cn) {
+                       if (_tok_match(cn->key, path, e)) {
+                               /* Inefficient */
+                               if (!cn_found)
+                                       cn_found = cn;
+                               else
+                                       log_warn("WARNING: Ignoring duplicate"
+                                                " config node: %s ("
+                                                "seeking %s)", cn->key, path);
+                       }
+
+                       cn = cn->sib;
+               }
+
+               if (cn_found && *e)
+                       cn = cn_found->child;
+               else
+                       break;  /* don't move into the last node */
+
+               path = e;
+       }
+
+       return cn_found;
+}
+
+static const struct dm_config_node *_find_first_config_node(const void *start, const char *path)
+{
+       const struct dm_config_tree *cft = start;
+       const struct dm_config_node *cn = NULL;
+
+       while (cft) {
+               if ((cn = _find_config_node(cft->root, path)))
+                       return cn;
+               cft = cft->cascade;
+       }
+
+       return NULL;
+}
+
+static const char *_find_config_str(const void *start, node_lookup_fn find_fn,
+                                   const char *path, const char *fail, int allow_empty)
+{
+       const struct dm_config_node *n = find_fn(start, path);
+
+       /* Empty strings are ignored if allow_empty is set */
+       if (n && n->v) {
+               if ((n->v->type == DM_CFG_STRING) &&
+                   (allow_empty || (*n->v->v.str))) {
+                       log_very_verbose("Setting %s to %s", path, n->v->v.str);
+                       return n->v->v.str;
+               }
+               if ((n->v->type != DM_CFG_STRING) || (!allow_empty && fail))
+                       log_warn("WARNING: Ignoring unsupported value for %s.", path);
+       }
+
+       if (fail)
+               log_very_verbose("%s not found in config: defaulting to %s",
+                                path, fail);
+       return fail;
+}
+
+const char *dm_config_find_str(const struct dm_config_node *cn,
+                              const char *path, const char *fail)
+{
+       return _find_config_str(cn, _find_config_node, path, fail, 0);
+}
+
+const char *dm_config_find_str_allow_empty(const struct dm_config_node *cn,
+                                          const char *path, const char *fail)
+{
+       return _find_config_str(cn, _find_config_node, path, fail, 1);
+}
+
+static int64_t _find_config_int64(const void *start, node_lookup_fn find,
+                                 const char *path, int64_t fail)
+{
+       const struct dm_config_node *n = find(start, path);
+
+       if (n && n->v && n->v->type == DM_CFG_INT) {
+               log_very_verbose("Setting %s to %" PRId64, path, n->v->v.i);
+               return n->v->v.i;
+       }
+
+       log_very_verbose("%s not found in config: defaulting to %" PRId64,
+                        path, fail);
+       return fail;
+}
+
+static float _find_config_float(const void *start, node_lookup_fn find,
+                               const char *path, float fail)
+{
+       const struct dm_config_node *n = find(start, path);
+
+       if (n && n->v && n->v->type == DM_CFG_FLOAT) {
+               log_very_verbose("Setting %s to %f", path, n->v->v.f);
+               return n->v->v.f;
+       }
+
+       log_very_verbose("%s not found in config: defaulting to %f",
+                        path, fail);
+
+       return fail;
+
+}
+
+static int _str_in_array(const char *str, const char * const values[])
+{
+       int i;
+
+       for (i = 0; values[i]; i++)
+               if (!strcasecmp(str, values[i]))
+                       return 1;
+
+       return 0;
+}
+
+static int _str_to_bool(const char *str, int fail)
+{
+       const char * const _true_values[]  = { "y", "yes", "on", "true", NULL };
+       const char * const _false_values[] = { "n", "no", "off", "false", NULL };
+
+       if (_str_in_array(str, _true_values))
+               return 1;
+
+       if (_str_in_array(str, _false_values))
+               return 0;
+
+       return fail;
+}
+
+static int _find_config_bool(const void *start, node_lookup_fn find,
+                            const char *path, int fail)
+{
+       const struct dm_config_node *n = find(start, path);
+       const struct dm_config_value *v;
+       int b;
+
+       if (n) {
+               v = n->v;
+
+               switch (v->type) {
+               case DM_CFG_INT:
+                       b = v->v.i ? 1 : 0;
+                       log_very_verbose("Setting %s to %d", path, b);
+                       return b;
+
+               case DM_CFG_STRING:
+                       b = _str_to_bool(v->v.str, fail);
+                       log_very_verbose("Setting %s to %d", path, b);
+                       return b;
+               default:
+                       ;
+               }
+       }
+
+       log_very_verbose("%s not found in config: defaulting to %d",
+                        path, fail);
+
+       return fail;
+}
+
+/***********************************
+ * node-based lookup
+ **/
+
+struct dm_config_node *dm_config_find_node(const struct dm_config_node *cn,
+                                          const char *path)
+{
+       return (struct dm_config_node *) _find_config_node(cn, path);
+}
+
+int dm_config_find_int(const struct dm_config_node *cn, const char *path, int fail)
+{
+       /* FIXME Add log_error message on overflow */
+       return (int) _find_config_int64(cn, _find_config_node, path, (int64_t) fail);
+}
+
+int64_t dm_config_find_int64(const struct dm_config_node *cn, const char *path, int64_t fail)
+{
+       return _find_config_int64(cn, _find_config_node, path, fail);
+}
+
+float dm_config_find_float(const struct dm_config_node *cn, const char *path,
+                          float fail)
+{
+       return _find_config_float(cn, _find_config_node, path, fail);
+}
+
+int dm_config_find_bool(const struct dm_config_node *cn, const char *path, int fail)
+{
+       return _find_config_bool(cn, _find_config_node, path, fail);
+}
+
+/***********************************
+ * tree-based lookup
+ **/
+
+const struct dm_config_node *dm_config_tree_find_node(const struct dm_config_tree *cft,
+                                                     const char *path)
+{
+       return _find_first_config_node(cft, path);
+}
+
+const char *dm_config_tree_find_str(const struct dm_config_tree *cft, const char *path,
+                                   const char *fail)
+{
+       return _find_config_str(cft, _find_first_config_node, path, fail, 0);
+}
+
+const char *dm_config_tree_find_str_allow_empty(const struct dm_config_tree *cft, const char *path,
+                                               const char *fail)
+{
+       return _find_config_str(cft, _find_first_config_node, path, fail, 1);
+}
+
+int dm_config_tree_find_int(const struct dm_config_tree *cft, const char *path, int fail)
+{
+       /* FIXME Add log_error message on overflow */
+       return (int) _find_config_int64(cft, _find_first_config_node, path, (int64_t) fail);
+}
+
+int64_t dm_config_tree_find_int64(const struct dm_config_tree *cft, const char *path, int64_t fail)
+{
+       return _find_config_int64(cft, _find_first_config_node, path, fail);
+}
+
+float dm_config_tree_find_float(const struct dm_config_tree *cft, const char *path,
+                               float fail)
+{
+       return _find_config_float(cft, _find_first_config_node, path, fail);
+}
+
+int dm_config_tree_find_bool(const struct dm_config_tree *cft, const char *path, int fail)
+{
+       return _find_config_bool(cft, _find_first_config_node, path, fail);
+}
+
+/************************************/
+
+
+int dm_config_get_uint32(const struct dm_config_node *cn, const char *path,
+                        uint32_t *result)
+{
+       const struct dm_config_node *n;
+
+       n = _find_config_node(cn, path);
+
+       if (!n || !n->v || n->v->type != DM_CFG_INT)
+               return 0;
+
+       if (result)
+               *result = n->v->v.i;
+       return 1;
+}
+
+int dm_config_get_uint64(const struct dm_config_node *cn, const char *path,
+                        uint64_t *result)
+{
+       const struct dm_config_node *n;
+
+       n = _find_config_node(cn, path);
+
+       if (!n || !n->v || n->v->type != DM_CFG_INT)
+               return 0;
+
+       if (result)
+               *result = (uint64_t) n->v->v.i;
+       return 1;
+}
+
+int dm_config_get_str(const struct dm_config_node *cn, const char *path,
+                     const char **result)
+{
+       const struct dm_config_node *n;
+
+       n = _find_config_node(cn, path);
+
+       if (!n || !n->v || n->v->type != DM_CFG_STRING)
+               return 0;
+
+       if (result)
+               *result = n->v->v.str;
+       return 1;
+}
+
+int dm_config_get_list(const struct dm_config_node *cn, const char *path,
+                      const struct dm_config_value **result)
+{
+       const struct dm_config_node *n;
+
+       n = _find_config_node(cn, path);
+       /* TODO when we represent single-item lists consistently, add a check
+        * for n->v->next != NULL */
+       if (!n || !n->v)
+               return 0;
+
+       if (result)
+               *result = n->v;
+       return 1;
+}
+
+int dm_config_get_section(const struct dm_config_node *cn, const char *path,
+                         const struct dm_config_node **result)
+{
+       const struct dm_config_node *n;
+
+       n = _find_config_node(cn, path);
+       if (!n || n->v)
+               return 0;
+
+       if (result)
+               *result = n;
+       return 1;
+}
+
+int dm_config_has_node(const struct dm_config_node *cn, const char *path)
+{
+       return _find_config_node(cn, path) ? 1 : 0;
+}
+
+/*
+ * Convert a token type to the char it represents.
+ */
+static char _token_type_to_char(int type)
+{
+       switch (type) {
+               case TOK_SECTION_B:
+                       return SECTION_B_CHAR;
+               case TOK_SECTION_E:
+                       return SECTION_E_CHAR;
+               default:
+                       return 0;
+       }
+}
+
+/*
+ * Returns:
+ *  # of 'type' tokens in 'str'.
+ */
+static unsigned _count_tokens(const char *str, unsigned len, int type)
+{
+       char c;
+
+       c = _token_type_to_char(type);
+
+       return dm_count_chars(str, len, c);
+}
+
+const char *dm_config_parent_name(const struct dm_config_node *n)
+{
+       return (n->parent ? n->parent->key : "(root)");
+}
+/*
+ * Heuristic function to make a quick guess as to whether a text
+ * region probably contains a valid config "section".  (Useful for
+ * scanning areas of the disk for old metadata.)
+ * Config sections contain various tokens, may contain other sections
+ * and strings, and are delimited by begin (type 'TOK_SECTION_B') and
+ * end (type 'TOK_SECTION_E') tokens.  As a quick heuristic, we just
+ * count the number of begin and end tokens, and see if they are
+ * non-zero and the counts match.
+ * Full validation of the section should be done with another function
+ * (for example, read_config_fd).
+ *
+ * Returns:
+ *  0 - probably is not a valid config section
+ *  1 - probably _is_ a valid config section
+ */
+unsigned dm_config_maybe_section(const char *str, unsigned len)
+{
+       int begin_count;
+       int end_count;
+
+       begin_count = _count_tokens(str, len, TOK_SECTION_B);
+       end_count = _count_tokens(str, len, TOK_SECTION_E);
+
+       if (begin_count && end_count && (begin_count == end_count))
+               return 1;
+       else
+               return 0;
+}
+
+__attribute__((nonnull(1, 2)))
+static struct dm_config_value *_clone_config_value(struct dm_pool *mem,
+                                                  const struct dm_config_value *v)
+{
+       struct dm_config_value *new_cv;
+
+       if (!(new_cv = _create_value(mem))) {
+               log_error("Failed to clone config value.");
+               return NULL;
+       }
+
+       new_cv->type = v->type;
+       if (v->type == DM_CFG_STRING) {
+               if (!(new_cv->v.str = dm_pool_strdup(mem, v->v.str))) {
+                       log_error("Failed to clone config string value.");
+                       return NULL;
+               }
+       } else
+               new_cv->v = v->v;
+
+       if (v->next && !(new_cv->next = _clone_config_value(mem, v->next)))
+               return_NULL;
+
+       return new_cv;
+}
+
+struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem, const struct dm_config_node *cn, int siblings)
+{
+       struct dm_config_node *new_cn;
+
+       if (!cn) {
+               log_error("Cannot clone NULL config node.");
+               return NULL;
+       }
+
+       if (!(new_cn = _create_node(mem))) {
+               log_error("Failed to clone config node.");
+               return NULL;
+       }
+
+       if ((cn->key && !(new_cn->key = dm_pool_strdup(mem, cn->key)))) {
+               log_error("Failed to clone config node key.");
+               return NULL;
+       }
+
+       if ((cn->v && !(new_cn->v = _clone_config_value(mem, cn->v))) ||
+           (cn->child && !(new_cn->child = dm_config_clone_node_with_mem(mem, cn->child, 1))) ||
+           (siblings && cn->sib && !(new_cn->sib = dm_config_clone_node_with_mem(mem, cn->sib, siblings))))
+               return_NULL; /* 'new_cn' released with mem pool */
+
+       return new_cn;
+}
+
+struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, const struct dm_config_node *node, int sib)
+{
+       return dm_config_clone_node_with_mem(cft->mem, node, sib);
+}
+
+struct dm_config_node *dm_config_create_node(struct dm_config_tree *cft, const char *key)
+{
+       struct dm_config_node *cn;
+
+       if (!(cn = _create_node(cft->mem))) {
+               log_error("Failed to create config node.");
+               return NULL;
+       }
+       if (!(cn->key = dm_pool_strdup(cft->mem, key))) {
+               log_error("Failed to create config node's key.");
+               return NULL;
+       }
+       cn->parent = NULL;
+       cn->v = NULL;
+
+       return cn;
+}
+
+struct dm_config_value *dm_config_create_value(struct dm_config_tree *cft)
+{
+       return _create_value(cft->mem);
+}
+
+struct dm_pool *dm_config_memory(struct dm_config_tree *cft)
+{
+       return cft->mem;
+}
index 8d0051494ebd249fea65b5e8e925ed4c9c4c5202..096eba2f0b893e8e2956f83813f83924dabf7df0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005-2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2005-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of the device-mapper userspace tools.
  *
@@ -16,7 +16,6 @@
 #include "libdm-targets.h"
 #include "libdm-common.h"
 #include "kdev_t.h"
-#include "dm-ioctl.h"
 
 #include <stdarg.h>
 #include <sys/param.h>
@@ -24,9 +23,6 @@
 
 #define MAX_TARGET_PARAMSIZE 500000
 
-/* FIXME Fix interface so this is used only by LVM */
-#define UUID_PREFIX "LVM-"
-
 #define REPLICATOR_LOCAL_SITE 0
 
 /* Supported segment types */
@@ -42,6 +38,19 @@ enum {
        SEG_SNAPSHOT_MERGE,
        SEG_STRIPED,
        SEG_ZERO,
+       SEG_THIN_POOL,
+       SEG_THIN,
+       SEG_RAID1,
+       SEG_RAID10,
+       SEG_RAID4,
+       SEG_RAID5_LA,
+       SEG_RAID5_RA,
+       SEG_RAID5_LS,
+       SEG_RAID5_RS,
+       SEG_RAID6_ZR,
+       SEG_RAID6_NR,
+       SEG_RAID6_NC,
+       SEG_LAST,
 };
 
 /* FIXME Add crypt and multipath support */
@@ -61,6 +70,26 @@ struct {
        { SEG_SNAPSHOT_MERGE, "snapshot-merge" },
        { SEG_STRIPED, "striped" },
        { SEG_ZERO, "zero"},
+       { SEG_THIN_POOL, "thin-pool"},
+       { SEG_THIN, "thin"},
+       { SEG_RAID1, "raid1"},
+       { SEG_RAID10, "raid10"},
+       { SEG_RAID4, "raid4"},
+       { SEG_RAID5_LA, "raid5_la"},
+       { SEG_RAID5_RA, "raid5_ra"},
+       { SEG_RAID5_LS, "raid5_ls"},
+       { SEG_RAID5_RS, "raid5_rs"},
+       { SEG_RAID6_ZR, "raid6_zr"},
+       { SEG_RAID6_NR, "raid6_nr"},
+       { SEG_RAID6_NC, "raid6_nc"},
+
+       /*
+        *WARNING: Since 'raid' target overloads this 1:1 mapping table
+        * for search do not add new enum elements past them!
+        */
+       { SEG_RAID5_LS, "raid5"}, /* same as "raid5_ls" (default for MD also) */
+       { SEG_RAID6_ZR, "raid6"}, /* same as "raid6_zr" */
+       { SEG_LAST, NULL },
 };
 
 /* Some segment types have a list of areas of other devices attached */
@@ -77,6 +106,32 @@ struct seg_area {
        uint32_t flags;                 /* Replicator sync log flags */
 };
 
+struct dm_thin_message {
+       dm_thin_message_t type;
+       union {
+               struct {
+                       uint32_t device_id;
+                       uint32_t origin_id;
+               } m_create_snap;
+               struct {
+                       uint32_t device_id;
+               } m_create_thin;
+               struct {
+                       uint32_t device_id;
+               } m_delete;
+               struct {
+                       uint64_t current_id;
+                       uint64_t new_id;
+               } m_set_transaction_id;
+       } u;
+};
+
+struct thin_message {
+       struct dm_list list;
+       struct dm_thin_message message;
+       int expected_errno;
+};
+
 /* Replicator-log has a list of sites */
 /* FIXME: maybe move to seg_area too? */
 struct replicator_site {
@@ -100,7 +155,7 @@ struct load_segment {
        unsigned area_count;            /* Linear + Striped + Mirrored + Crypt + Replicator */
        struct dm_list areas;           /* Linear + Striped + Mirrored + Crypt + Replicator */
 
-       uint32_t stripe_size;           /* Striped */
+       uint32_t stripe_size;           /* Striped + raid */
 
        int persistent;                 /* Snapshot */
        uint32_t chunk_size;            /* Snapshot */
@@ -109,7 +164,7 @@ struct load_segment {
        struct dm_tree_node *merge;     /* Snapshot */
 
        struct dm_tree_node *log;       /* Mirror + Replicator */
-       uint32_t region_size;           /* Mirror */
+       uint32_t region_size;           /* Mirror + raid */
        unsigned clustered;             /* Mirror */
        unsigned mirror_area_count;     /* Mirror */
        uint32_t flags;                 /* Mirror log */
@@ -127,6 +182,21 @@ struct load_segment {
        unsigned rdevice_count;         /* Replicator */
        struct dm_tree_node *replicator;/* Replicator-dev */
        uint64_t rdevice_index;         /* Replicator-dev */
+
+       uint64_t rebuilds;            /* raid */
+
+       struct dm_tree_node *metadata;  /* Thin_pool */
+       struct dm_tree_node *pool;      /* Thin_pool, Thin */
+       struct dm_tree_node *external;  /* Thin */
+       struct dm_list thin_messages;   /* Thin_pool */
+       uint64_t transaction_id;        /* Thin_pool */
+       uint64_t low_water_mark;        /* Thin_pool */
+       uint32_t data_block_size;       /* Thin_pool */
+       unsigned skip_block_zeroing;    /* Thin_pool */
+       unsigned ignore_discard;        /* Thin_pool target vsn 1.1 */
+       unsigned no_discard_passdown;   /* Thin_pool target vsn 1.1 */
+       uint32_t device_id;             /* Thin */
+
 };
 
 /* Per-device properties */
@@ -149,7 +219,19 @@ struct load_properties {
         * and processing of dm tree). This will also flush all stacked dev
         * node operations, synchronizing with udev.
         */
-       int immediate_dev_node;
+       unsigned immediate_dev_node;
+
+       /*
+        * If the device size changed from zero and this is set,
+        * don't resume the device immediately, even if the device
+        * has parents.  This works provided the parents do not
+        * validate the device size and is required by pvmove to
+        * avoid starting the mirror resync operation too early.
+        */
+       unsigned delay_resume_if_new;
+
+       /* Send messages for this node in preload */
+       unsigned send_messages;
 };
 
 /* Two of these used to join two nodes with uses and used_by. */
@@ -161,12 +243,12 @@ struct dm_tree_link {
 struct dm_tree_node {
        struct dm_tree *dtree;
 
-        const char *name;
-        const char *uuid;
-        struct dm_info info;
+       const char *name;
+       const char *uuid;
+       struct dm_info info;
 
-        struct dm_list uses;           /* Nodes this node uses */
-        struct dm_list used_by;        /* Nodes that use this node */
+       struct dm_list uses;            /* Nodes this node uses */
+       struct dm_list used_by;         /* Nodes that use this node */
 
        int activation_priority;        /* 0 gets activated first */
 
@@ -181,6 +263,10 @@ struct dm_tree_node {
         * Note: only direct child is allowed
         */
        struct dm_tree_node *presuspend_node;
+
+       /* Callback */
+       dm_node_callback_fn callback;
+       void *callback_data;
 };
 
 struct dm_tree {
@@ -189,16 +275,24 @@ struct dm_tree {
        struct dm_hash_table *uuids;
        struct dm_tree_node root;
        int skip_lockfs;                /* 1 skips lockfs (for non-snapshots) */
-       int no_flush;           /* 1 sets noflush (mirrors/multipath) */
+       int no_flush;                   /* 1 sets noflush (mirrors/multipath) */
+       int retry_remove;               /* 1 retries remove if not successful */
        uint32_t cookie;
 };
 
+/*
+ * Tree functions.
+ */
 struct dm_tree *dm_tree_create(void)
 {
+       struct dm_pool *dmem;
        struct dm_tree *dtree;
 
-       if (!(dtree = dm_zalloc(sizeof(*dtree)))) {
-               log_error("dm_tree_create malloc failed");
+       if (!(dmem = dm_pool_create("dtree", 1024)) ||
+           !(dtree = dm_pool_zalloc(dmem, sizeof(*dtree)))) {
+               log_error("Failed to allocate dtree.");
+               if (dmem)
+                       dm_pool_destroy(dmem);
                return NULL;
        }
 
@@ -207,17 +301,11 @@ struct dm_tree *dm_tree_create(void)
        dm_list_init(&dtree->root.used_by);
        dtree->skip_lockfs = 0;
        dtree->no_flush = 0;
-
-       if (!(dtree->mem = dm_pool_create("dtree", 1024))) {
-               log_error("dtree pool creation failed");
-               dm_free(dtree);
-               return NULL;
-       }
+       dtree->mem = dmem;
 
        if (!(dtree->devs = dm_hash_create(8))) {
                log_error("dtree hash creation failed");
                dm_pool_destroy(dtree->mem);
-               dm_free(dtree);
                return NULL;
        }
 
@@ -225,7 +313,6 @@ struct dm_tree *dm_tree_create(void)
                log_error("dtree uuid hash creation failed");
                dm_hash_destroy(dtree->devs);
                dm_pool_destroy(dtree->mem);
-               dm_free(dtree);
                return NULL;
        }
 
@@ -240,9 +327,36 @@ void dm_tree_free(struct dm_tree *dtree)
        dm_hash_destroy(dtree->uuids);
        dm_hash_destroy(dtree->devs);
        dm_pool_destroy(dtree->mem);
-       dm_free(dtree);
 }
 
+void dm_tree_set_cookie(struct dm_tree_node *node, uint32_t cookie)
+{
+       node->dtree->cookie = cookie;
+}
+
+uint32_t dm_tree_get_cookie(struct dm_tree_node *node)
+{
+       return node->dtree->cookie;
+}
+
+void dm_tree_skip_lockfs(struct dm_tree_node *dnode)
+{
+       dnode->dtree->skip_lockfs = 1;
+}
+
+void dm_tree_use_no_flush_suspend(struct dm_tree_node *dnode)
+{
+       dnode->dtree->no_flush = 1;
+}
+
+void dm_tree_retry_remove(struct dm_tree_node *dnode)
+{
+       dnode->dtree->retry_remove = 1;
+}
+
+/*
+ * Node functions.
+ */
 static int _nodes_are_linked(const struct dm_tree_node *parent,
                             const struct dm_tree_node *child)
 {
@@ -329,13 +443,13 @@ static void _remove_from_bottomlevel(struct dm_tree_node *node)
 static int _link_tree_nodes(struct dm_tree_node *parent, struct dm_tree_node *child)
 {
        /* Don't link to root node if child already has a parent */
-       if ((parent == &parent->dtree->root)) {
+       if (parent == &parent->dtree->root) {
                if (dm_tree_node_num_children(child, 1))
                        return 1;
        } else
                _remove_from_toplevel(child);
 
-       if ((child == &child->dtree->root)) {
+       if (child == &child->dtree->root) {
                if (dm_tree_node_num_children(parent, 0))
                        return 1;
        } else
@@ -352,7 +466,7 @@ static struct dm_tree_node *_create_dm_tree_node(struct dm_tree *dtree,
                                                 uint16_t udev_flags)
 {
        struct dm_tree_node *node;
-       uint64_t dev;
+       dev_t dev;
 
        if (!(node = dm_pool_zalloc(dtree->mem, sizeof(*node)))) {
                log_error("_create_dm_tree_node alloc failed");
@@ -372,7 +486,7 @@ static struct dm_tree_node *_create_dm_tree_node(struct dm_tree *dtree,
        dm_list_init(&node->used_by);
        dm_list_init(&node->props.segs);
 
-       dev = MKDEV(info->major, info->minor);
+       dev = MKDEV((dev_t)info->major, info->minor);
 
        if (!dm_hash_insert_binary(dtree->devs, (const char *) &dev,
                                sizeof(dev), node)) {
@@ -396,7 +510,7 @@ static struct dm_tree_node *_create_dm_tree_node(struct dm_tree *dtree,
 static struct dm_tree_node *_find_dm_tree_node(struct dm_tree *dtree,
                                               uint32_t major, uint32_t minor)
 {
-       uint64_t dev = MKDEV(major, minor);
+       dev_t dev = MKDEV((dev_t)major, minor);
 
        return dm_hash_lookup_binary(dtree->devs, (const char *) &dev,
                                  sizeof(dev));
@@ -406,32 +520,229 @@ static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree,
                                                       const char *uuid)
 {
        struct dm_tree_node *node;
+       const char *default_uuid_prefix;
+       size_t default_uuid_prefix_len;
 
        if ((node = dm_hash_lookup(dtree->uuids, uuid)))
                return node;
 
-       if (strncmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1))
+       default_uuid_prefix = dm_uuid_prefix();
+       default_uuid_prefix_len = strlen(default_uuid_prefix);
+
+       if (strncmp(uuid, default_uuid_prefix, default_uuid_prefix_len))
                return NULL;
 
-       return dm_hash_lookup(dtree->uuids, uuid + sizeof(UUID_PREFIX) - 1);
+       return dm_hash_lookup(dtree->uuids, uuid + default_uuid_prefix_len);
+}
+
+void dm_tree_node_set_udev_flags(struct dm_tree_node *dnode, uint16_t udev_flags)
+
+{
+       struct dm_info *dinfo = &dnode->info;
+
+       if (udev_flags != dnode->udev_flags)
+               log_debug("Resetting %s (%" PRIu32 ":%" PRIu32
+                         ") udev_flags from 0x%x to 0x%x",
+                         dnode->name, dinfo->major, dinfo->minor,
+                         dnode->udev_flags, udev_flags);
+       dnode->udev_flags = udev_flags;
+}
+
+void dm_tree_node_set_read_ahead(struct dm_tree_node *dnode,
+                                uint32_t read_ahead,
+                                uint32_t read_ahead_flags)
+{
+       dnode->props.read_ahead = read_ahead;
+       dnode->props.read_ahead_flags = read_ahead_flags;
+}
+
+void dm_tree_node_set_presuspend_node(struct dm_tree_node *node,
+                                     struct dm_tree_node *presuspend_node)
+{
+       node->presuspend_node = presuspend_node;
+}
+
+const char *dm_tree_node_get_name(const struct dm_tree_node *node)
+{
+       return node->info.exists ? node->name : "";
+}
+
+const char *dm_tree_node_get_uuid(const struct dm_tree_node *node)
+{
+       return node->info.exists ? node->uuid : "";
+}
+
+const struct dm_info *dm_tree_node_get_info(const struct dm_tree_node *node)
+{
+       return &node->info;
+}
+
+void *dm_tree_node_get_context(const struct dm_tree_node *node)
+{
+       return node->context;
+}
+
+int dm_tree_node_size_changed(const struct dm_tree_node *dnode)
+{
+       return dnode->props.size_changed;
+}
+
+int dm_tree_node_num_children(const struct dm_tree_node *node, uint32_t inverted)
+{
+       if (inverted) {
+               if (_nodes_are_linked(&node->dtree->root, node))
+                       return 0;
+               return dm_list_size(&node->used_by);
+       }
+
+       if (_nodes_are_linked(node, &node->dtree->root))
+               return 0;
+
+       return dm_list_size(&node->uses);
+}
+
+/*
+ * Returns 1 if no prefix supplied
+ */
+static int _uuid_prefix_matches(const char *uuid, const char *uuid_prefix, size_t uuid_prefix_len)
+{
+       const char *default_uuid_prefix = dm_uuid_prefix();
+       size_t default_uuid_prefix_len = strlen(default_uuid_prefix);
+
+       if (!uuid_prefix)
+               return 1;
+
+       if (!strncmp(uuid, uuid_prefix, uuid_prefix_len))
+               return 1;
+
+       /* Handle transition: active device uuids might be missing the prefix */
+       if (uuid_prefix_len <= 4)
+               return 0;
+
+       if (!strncmp(uuid, default_uuid_prefix, default_uuid_prefix_len))
+               return 0;
+
+       if (strncmp(uuid_prefix, default_uuid_prefix, default_uuid_prefix_len))
+               return 0;
+
+       if (!strncmp(uuid, uuid_prefix + default_uuid_prefix_len, uuid_prefix_len - default_uuid_prefix_len))
+               return 1;
+
+       return 0;
+}
+
+/*
+ * Returns 1 if no children.
+ */
+static int _children_suspended(struct dm_tree_node *node,
+                              uint32_t inverted,
+                              const char *uuid_prefix,
+                              size_t uuid_prefix_len)
+{
+       struct dm_list *list;
+       struct dm_tree_link *dlink;
+       const struct dm_info *dinfo;
+       const char *uuid;
+
+       if (inverted) {
+               if (_nodes_are_linked(&node->dtree->root, node))
+                       return 1;
+               list = &node->used_by;
+       } else {
+               if (_nodes_are_linked(node, &node->dtree->root))
+                       return 1;
+               list = &node->uses;
+       }
+
+       dm_list_iterate_items(dlink, list) {
+               if (!(uuid = dm_tree_node_get_uuid(dlink->node))) {
+                       stack;
+                       continue;
+               }
+
+               /* Ignore if it doesn't belong to this VG */
+               if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
+                       continue;
+
+               /* Ignore if parent node wants to presuspend this node */
+               if (dlink->node->presuspend_node == node)
+                       continue;
+
+               if (!(dinfo = dm_tree_node_get_info(dlink->node))) {
+                       stack;  /* FIXME Is this normal? */
+                       return 0;
+               }
+
+               if (!dinfo->suspended)
+                       return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * Set major and minor to zero for root of tree.
+ */
+struct dm_tree_node *dm_tree_find_node(struct dm_tree *dtree,
+                                         uint32_t major,
+                                         uint32_t minor)
+{
+       if (!major && !minor)
+               return &dtree->root;
+
+       return _find_dm_tree_node(dtree, major, minor);
+}
+
+/*
+ * Set uuid to NULL for root of tree.
+ */
+struct dm_tree_node *dm_tree_find_node_by_uuid(struct dm_tree *dtree,
+                                                 const char *uuid)
+{
+       if (!uuid || !*uuid)
+               return &dtree->root;
+
+       return _find_dm_tree_node_by_uuid(dtree, uuid);
+}
+
+/*
+ * First time set *handle to NULL.
+ * Set inverted to invert the tree.
+ */
+struct dm_tree_node *dm_tree_next_child(void **handle,
+                                       const struct dm_tree_node *parent,
+                                       uint32_t inverted)
+{
+       struct dm_list **dlink = (struct dm_list **) handle;
+       const struct dm_list *use_list;
+
+       if (inverted)
+               use_list = &parent->used_by;
+       else
+               use_list = &parent->uses;
+
+       if (!*dlink)
+               *dlink = dm_list_first(use_list);
+       else
+               *dlink = dm_list_next(use_list, *dlink);
+
+       return (*dlink) ? dm_list_item(*dlink, struct dm_tree_link)->node : NULL;
 }
 
 static int _deps(struct dm_task **dmt, struct dm_pool *mem, uint32_t major, uint32_t minor,
-                const char **name, const char **uuid,
+                const char **name, const char **uuid, unsigned inactive_table,
                 struct dm_info *info, struct dm_deps **deps)
 {
        memset(info, 0, sizeof(*info));
 
        if (!dm_is_dm_major(major)) {
-               *name = "";
-               *uuid = "";
+               if (name)
+                       *name = "";
+               if (uuid)
+                       *uuid = "";
                *deps = NULL;
                info->major = major;
                info->minor = minor;
-               info->exists = 0;
-               info->live_table = 0;
-               info->inactive_table = 0;
-               info->read_only = 0;
                return 1;
        }
 
@@ -452,6 +763,12 @@ static int _deps(struct dm_task **dmt, struct dm_pool *mem, uint32_t major, uint
                goto failed;
        }
 
+       if (inactive_table && !dm_task_query_inactive_table(*dmt)) {
+               log_error("_deps: failed to set inactive table for (%" PRIu32 ":%" PRIu32 ")",
+                         major, minor);
+               goto failed;
+       }
+
        if (!dm_task_run(*dmt)) {
                log_error("_deps: task run failed for (%" PRIu32 ":%" PRIu32 ")",
                          major, minor);
@@ -465,8 +782,10 @@ static int _deps(struct dm_task **dmt, struct dm_pool *mem, uint32_t major, uint
        }
 
        if (!info->exists) {
-               *name = "";
-               *uuid = "";
+               if (name)
+                       *name = "";
+               if (uuid)
+                       *uuid = "";
                *deps = NULL;
        } else {
                if (info->major != major) {
@@ -479,11 +798,11 @@ static int _deps(struct dm_task **dmt, struct dm_pool *mem, uint32_t major, uint
                                  minor, info->minor);
                        goto failed;
                }
-               if (!(*name = dm_pool_strdup(mem, dm_task_get_name(*dmt)))) {
+               if (name && !(*name = dm_pool_strdup(mem, dm_task_get_name(*dmt)))) {
                        log_error("name pool_strdup failed");
                        goto failed;
                }
-               if (!(*uuid = dm_pool_strdup(mem, dm_task_get_uuid(*dmt)))) {
+               if (uuid && !(*uuid = dm_pool_strdup(mem, dm_task_get_uuid(*dmt)))) {
                        log_error("uuid pool_strdup failed");
                        goto failed;
                }
@@ -497,490 +816,404 @@ failed:
        return 0;
 }
 
-static struct dm_tree_node *_add_dev(struct dm_tree *dtree,
-                                    struct dm_tree_node *parent,
-                                    uint32_t major, uint32_t minor,
-                                    uint16_t udev_flags)
+/*
+ * Deactivate a device with its dependencies if the uuid prefix matches.
+ */
+static int _info_by_dev(uint32_t major, uint32_t minor, int with_open_count,
+                       struct dm_info *info, struct dm_pool *mem,
+                       const char **name, const char **uuid)
 {
-       struct dm_task *dmt = NULL;
-       struct dm_info info;
-       struct dm_deps *deps = NULL;
-       const char *name = NULL;
-       const char *uuid = NULL;
-       struct dm_tree_node *node = NULL;
-       uint32_t i;
-       int new = 0;
+       struct dm_task *dmt;
+       int r;
 
-       /* Already in tree? */
-       if (!(node = _find_dm_tree_node(dtree, major, minor))) {
-               if (!_deps(&dmt, dtree->mem, major, minor, &name, &uuid, &info, &deps))
-                       return_NULL;
+       if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
+               log_error("_info_by_dev: dm_task creation failed");
+               return 0;
+       }
 
-               if (!(node = _create_dm_tree_node(dtree, name, uuid, &info,
-                                                 NULL, udev_flags)))
-                       goto_out;
-               new = 1;
+       if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
+               log_error("_info_by_dev: Failed to set device number");
+               dm_task_destroy(dmt);
+               return 0;
        }
 
-       if (!_link_tree_nodes(parent, node)) {
-               node = NULL;
+       if (!with_open_count && !dm_task_no_open_count(dmt))
+               log_error("Failed to disable open_count");
+
+       if (!(r = dm_task_run(dmt)))
                goto_out;
-       }
 
-       /* If node was already in tree, no need to recurse. */
-       if (!new)
-               goto out;
+       if (!(r = dm_task_get_info(dmt, info)))
+               goto_out;
 
-       /* Can't recurse if not a mapped device or there are no dependencies */
-       if (!node->info.exists || !deps->count) {
-               if (!_add_to_bottomlevel(node)) {
-                       stack;
-                       node = NULL;
-               }
-               goto out;
+       if (name && !(*name = dm_pool_strdup(mem, dm_task_get_name(dmt)))) {
+               log_error("name pool_strdup failed");
+               r = 0;
+               goto_out;
        }
 
-       /* Add dependencies to tree */
-       for (i = 0; i < deps->count; i++)
-               if (!_add_dev(dtree, node, MAJOR(deps->device[i]),
-                             MINOR(deps->device[i]), udev_flags)) {
-                       node = NULL;
-                       goto_out;
-               }
+       if (uuid && !(*uuid = dm_pool_strdup(mem, dm_task_get_uuid(dmt)))) {
+               log_error("uuid pool_strdup failed");
+               r = 0;
+               goto_out;
+       }
 
 out:
-       if (dmt)
-               dm_task_destroy(dmt);
+       dm_task_destroy(dmt);
 
-       return node;
+       return r;
 }
 
-static int _node_clear_table(struct dm_tree_node *dnode)
+static int _check_device_not_in_use(const char *name, struct dm_info *info)
 {
-       struct dm_task *dmt;
-       struct dm_info *info;
-       const char *name;
-       int r;
-
-       if (!(info = &dnode->info)) {
-               log_error("_node_clear_table failed: missing info");
-               return 0;
-       }
-
-       if (!(name = dm_tree_node_get_name(dnode))) {
-               log_error("_node_clear_table failed: missing name");
-               return 0;
-       }
-
-       /* Is there a table? */
-       if (!info->exists || !info->inactive_table)
+       if (!info->exists)
                return 1;
 
-       log_verbose("Clearing inactive table %s (%" PRIu32 ":%" PRIu32 ")",
-                   name, info->major, info->minor);
+       /* If sysfs is not used, use open_count information only. */
+       if (!*dm_sysfs_dir()) {
+               if (info->open_count) {
+                       log_error("Device %s (%" PRIu32 ":%" PRIu32 ") in use",
+                                 name, info->major, info->minor);
+                       return 0;
+               }
 
-       if (!(dmt = dm_task_create(DM_DEVICE_CLEAR))) {
-               log_error("Table clear dm_task creation failed for %s", name);
-               return 0;
+               return 1;
        }
 
-       if (!dm_task_set_major(dmt, info->major) ||
-           !dm_task_set_minor(dmt, info->minor)) {
-               log_error("Failed to set device number for %s table clear", name);
-               dm_task_destroy(dmt);
+       if (dm_device_has_holders(info->major, info->minor)) {
+               log_error("Device %s (%" PRIu32 ":%" PRIu32 ") is used "
+                         "by another device.", name, info->major, info->minor);
                return 0;
        }
 
-       r = dm_task_run(dmt);
-
-       if (!dm_task_get_info(dmt, info)) {
-               log_error("_node_clear_table failed: info missing after running task for %s", name);
-               r = 0;
+       if (dm_device_has_mounted_fs(info->major, info->minor)) {
+               log_error("Device %s (%" PRIu32 ":%" PRIu32 ") contains "
+                         "a filesystem in use.", name, info->major, info->minor);
+               return 0;
        }
 
-       dm_task_destroy(dmt);
-
-       return r;
+       return 1;
 }
 
-struct dm_tree_node *dm_tree_add_new_dev(struct dm_tree *dtree,
-                                           const char *name,
-                                           const char *uuid,
-                                           uint32_t major, uint32_t minor,
-                                           int read_only,
-                                           int clear_inactive,
-                                           void *context)
+/* Check if all parent nodes of given node have open_count == 0 */
+static int _node_has_closed_parents(struct dm_tree_node *node,
+                                   const char *uuid_prefix,
+                                   size_t uuid_prefix_len)
 {
-       struct dm_tree_node *dnode;
+       struct dm_tree_link *dlink;
+       const struct dm_info *dinfo;
        struct dm_info info;
-       const char *name2;
-       const char *uuid2;
+       const char *uuid;
 
-       /* Do we need to add node to tree? */
-       if (!(dnode = dm_tree_find_node_by_uuid(dtree, uuid))) {
-               if (!(name2 = dm_pool_strdup(dtree->mem, name))) {
-                       log_error("name pool_strdup failed");
-                       return NULL;
-               }
-               if (!(uuid2 = dm_pool_strdup(dtree->mem, uuid))) {
-                       log_error("uuid pool_strdup failed");
-                       return NULL;
+       /* Iterate through parents of this node */
+       dm_list_iterate_items(dlink, &node->used_by) {
+               if (!(uuid = dm_tree_node_get_uuid(dlink->node))) {
+                       stack;
+                       continue;
                }
 
-               info.major = 0;
-               info.minor = 0;
-               info.exists = 0;
-               info.live_table = 0;
-               info.inactive_table = 0;
-               info.read_only = 0;
+               /* Ignore if it doesn't belong to this VG */
+               if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
+                       continue;
 
-               if (!(dnode = _create_dm_tree_node(dtree, name2, uuid2, &info,
-                                                  context, 0)))
-                       return_NULL;
+               if (!(dinfo = dm_tree_node_get_info(dlink->node))) {
+                       stack;  /* FIXME Is this normal? */
+                       return 0;
+               }
 
-               /* Attach to root node until a table is supplied */
-               if (!_add_to_toplevel(dnode) || !_add_to_bottomlevel(dnode))
-                       return_NULL;
+               /* Refresh open_count */
+               if (!_info_by_dev(dinfo->major, dinfo->minor, 1, &info, NULL, NULL, NULL) ||
+                   !info.exists)
+                       continue;
 
-               dnode->props.major = major;
-               dnode->props.minor = minor;
-               dnode->props.new_name = NULL;
-               dnode->props.size_changed = 0;
-       } else if (strcmp(name, dnode->name)) {
-               /* Do we need to rename node? */
-               if (!(dnode->props.new_name = dm_pool_strdup(dtree->mem, name))) {
-                       log_error("name pool_strdup failed");
+               if (info.open_count) {
+                       log_debug("Node %s %d:%d has open_count %d", uuid_prefix,
+                                 dinfo->major, dinfo->minor, info.open_count);
                        return 0;
                }
        }
 
-       dnode->props.read_only = read_only ? 1 : 0;
-       dnode->props.read_ahead = DM_READ_AHEAD_AUTO;
-       dnode->props.read_ahead_flags = 0;
-
-       if (clear_inactive && !_node_clear_table(dnode))
-               return_NULL;
-
-       dnode->context = context;
-       dnode->udev_flags = 0;
-
-       return dnode;
+       return 1;
 }
 
-struct dm_tree_node *dm_tree_add_new_dev_with_udev_flags(struct dm_tree *dtree,
-                                                        const char *name,
-                                                        const char *uuid,
-                                                        uint32_t major,
-                                                        uint32_t minor,
-                                                        int read_only,
-                                                        int clear_inactive,
-                                                        void *context,
-                                                        uint16_t udev_flags)
+static int _deactivate_node(const char *name, uint32_t major, uint32_t minor,
+                           uint32_t *cookie, uint16_t udev_flags, int retry)
 {
-       struct dm_tree_node *node;
+       struct dm_task *dmt;
+       int r = 0;
 
-       if ((node = dm_tree_add_new_dev(dtree, name, uuid, major, minor, read_only,
-                                      clear_inactive, context)))
-               node->udev_flags = udev_flags;
+       log_verbose("Removing %s (%" PRIu32 ":%" PRIu32 ")", name, major, minor);
 
-       return node;
-}
+       if (!(dmt = dm_task_create(DM_DEVICE_REMOVE))) {
+               log_error("Deactivation dm_task creation failed for %s", name);
+               return 0;
+       }
 
+       if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
+               log_error("Failed to set device number for %s deactivation", name);
+               goto out;
+       }
 
-void dm_tree_node_set_read_ahead(struct dm_tree_node *dnode,
-                                uint32_t read_ahead,
-                                uint32_t read_ahead_flags)
-{
-       dnode->props.read_ahead = read_ahead;
-       dnode->props.read_ahead_flags = read_ahead_flags;
-}
+       if (!dm_task_no_open_count(dmt))
+               log_error("Failed to disable open_count");
 
-void dm_tree_node_set_presuspend_node(struct dm_tree_node *node,
-                                     struct dm_tree_node *presuspend_node)
-{
-       node->presuspend_node = presuspend_node;
-}
+       if (cookie)
+               if (!dm_task_set_cookie(dmt, cookie, udev_flags))
+                       goto out;
 
-int dm_tree_add_dev(struct dm_tree *dtree, uint32_t major, uint32_t minor)
-{
-       return _add_dev(dtree, &dtree->root, major, minor, 0) ? 1 : 0;
-}
+       if (retry)
+               dm_task_retry_remove(dmt);
 
-int dm_tree_add_dev_with_udev_flags(struct dm_tree *dtree, uint32_t major,
-                                   uint32_t minor, uint16_t udev_flags)
-{
-       return _add_dev(dtree, &dtree->root, major, minor, udev_flags) ? 1 : 0;
-}
+       r = dm_task_run(dmt);
 
-const char *dm_tree_node_get_name(const struct dm_tree_node *node)
-{
-       return node->info.exists ? node->name : "";
-}
+       /* FIXME Until kernel returns actual name so dm-iface.c can handle it */
+       rm_dev_node(name, dmt->cookie_set && !(udev_flags & DM_UDEV_DISABLE_DM_RULES_FLAG),
+                   dmt->cookie_set && (udev_flags & DM_UDEV_DISABLE_LIBRARY_FALLBACK));
 
-const char *dm_tree_node_get_uuid(const struct dm_tree_node *node)
-{
-       return node->info.exists ? node->uuid : "";
-}
+       /* FIXME Remove node from tree or mark invalid? */
 
-const struct dm_info *dm_tree_node_get_info(const struct dm_tree_node *node)
-{
-       return &node->info;
-}
+out:
+       dm_task_destroy(dmt);
 
-void *dm_tree_node_get_context(const struct dm_tree_node *node)
-{
-       return node->context;
+       return r;
 }
 
-int dm_tree_node_size_changed(const struct dm_tree_node *dnode)
+static int _node_clear_table(struct dm_tree_node *dnode, uint16_t udev_flags)
 {
-       return dnode->props.size_changed;
-}
+       struct dm_task *dmt = NULL, *deps_dmt = NULL;
+       struct dm_info *info, deps_info;
+       struct dm_deps *deps = NULL;
+       const char *name, *uuid;
+       const char *default_uuid_prefix;
+       size_t default_uuid_prefix_len;
+       uint32_t i;
+       int r = 0;
 
-int dm_tree_node_num_children(const struct dm_tree_node *node, uint32_t inverted)
-{
-       if (inverted) {
-               if (_nodes_are_linked(&node->dtree->root, node))
-                       return 0;
-               return dm_list_size(&node->used_by);
+       if (!(info = &dnode->info)) {
+               log_error("_node_clear_table failed: missing info");
+               return 0;
        }
 
-       if (_nodes_are_linked(node, &node->dtree->root))
+       if (!(name = dm_tree_node_get_name(dnode))) {
+               log_error("_node_clear_table failed: missing name");
                return 0;
+       }
 
-       return dm_list_size(&node->uses);
-}
-
-/*
- * Returns 1 if no prefix supplied
- */
-static int _uuid_prefix_matches(const char *uuid, const char *uuid_prefix, size_t uuid_prefix_len)
-{
-       if (!uuid_prefix)
-               return 1;
-
-       if (!strncmp(uuid, uuid_prefix, uuid_prefix_len))
+       /* Is there a table? */
+       if (!info->exists || !info->inactive_table)
                return 1;
 
-       /* Handle transition: active device uuids might be missing the prefix */
-       if (uuid_prefix_len <= 4)
-               return 0;
-
-       if (!strncmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1))
+       /* Get devices used by inactive table that's about to be deleted. */
+       if (!_deps(&deps_dmt, dnode->dtree->mem, info->major, info->minor, NULL, NULL, 1, info, &deps)) {
+               log_error("Failed to obtain dependencies for %s before clearing table.", name);
                return 0;
+       }
 
-       if (strncmp(uuid_prefix, UUID_PREFIX, sizeof(UUID_PREFIX) - 1))
-               return 0;
+       log_verbose("Clearing inactive table %s (%" PRIu32 ":%" PRIu32 ")",
+                   name, info->major, info->minor);
 
-       if (!strncmp(uuid, uuid_prefix + sizeof(UUID_PREFIX) - 1, uuid_prefix_len - (sizeof(UUID_PREFIX) - 1)))
-               return 1;
+       if (!(dmt = dm_task_create(DM_DEVICE_CLEAR))) {
+               log_error("Table clear dm_task creation failed for %s", name);
+               goto_out;
+       }
 
-       return 0;
-}
+       if (!dm_task_set_major(dmt, info->major) ||
+           !dm_task_set_minor(dmt, info->minor)) {
+               log_error("Failed to set device number for %s table clear", name);
+               goto_out;
+       }
 
-/*
- * Returns 1 if no children.
- */
-static int _children_suspended(struct dm_tree_node *node,
-                              uint32_t inverted,
-                              const char *uuid_prefix,
-                              size_t uuid_prefix_len)
-{
-       struct dm_list *list;
-       struct dm_tree_link *dlink;
-       const struct dm_info *dinfo;
-       const char *uuid;
+       r = dm_task_run(dmt);
 
-       if (inverted) {
-               if (_nodes_are_linked(&node->dtree->root, node))
-                       return 1;
-               list = &node->used_by;
-       } else {
-               if (_nodes_are_linked(node, &node->dtree->root))
-                       return 1;
-               list = &node->uses;
+       if (!dm_task_get_info(dmt, info)) {
+               log_error("_node_clear_table failed: info missing after running task for %s", name);
+               r = 0;
        }
 
-       dm_list_iterate_items(dlink, list) {
-               if (!(uuid = dm_tree_node_get_uuid(dlink->node))) {
-                       stack;
+       if (!r || !deps)
+               goto_out;
+
+       /*
+        * Remove (incomplete) devices that the inactive table referred to but
+        * which are not in the tree, no longer referenced and don't have a live
+        * table.
+        */
+       default_uuid_prefix = dm_uuid_prefix();
+       default_uuid_prefix_len = strlen(default_uuid_prefix);
+
+       for (i = 0; i < deps->count; i++) {
+               /* If already in tree, assume it's under control */
+               if (_find_dm_tree_node(dnode->dtree, MAJOR(deps->device[i]), MINOR(deps->device[i])))
                        continue;
-               }
 
-               /* Ignore if it doesn't belong to this VG */
-               if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
+               if (!_info_by_dev(MAJOR(deps->device[i]), MINOR(deps->device[i]), 1,
+                                 &deps_info, dnode->dtree->mem, &name, &uuid))
                        continue;
 
-               /* Ignore if parent node wants to presuspend this node */
-               if (dlink->node->presuspend_node == node)
+               /* Proceed if device is an 'orphan' - unreferenced and without a live table. */
+               if (!deps_info.exists || deps_info.live_table || deps_info.open_count)
                        continue;
 
-               if (!(dinfo = dm_tree_node_get_info(dlink->node))) {
-                       stack;  /* FIXME Is this normal? */
-                       return 0;
-               }
+               if (strncmp(uuid, default_uuid_prefix, default_uuid_prefix_len))
+                       continue;
 
-               if (!dinfo->suspended)
-                       return 0;
+               /* Remove device. */
+               if (!_deactivate_node(name, deps_info.major, deps_info.minor, &dnode->dtree->cookie, udev_flags, 0)) {
+                       log_error("Failed to deactivate no-longer-used device %s (%"
+                                 PRIu32 ":%" PRIu32 ")", name, deps_info.major, deps_info.minor);
+               } else if (deps_info.suspended)
+                       dec_suspended();
        }
 
-       return 1;
-}
-
-/*
- * Set major and minor to zero for root of tree.
- */
-struct dm_tree_node *dm_tree_find_node(struct dm_tree *dtree,
-                                         uint32_t major,
-                                         uint32_t minor)
-{
-       if (!major && !minor)
-               return &dtree->root;
-
-       return _find_dm_tree_node(dtree, major, minor);
-}
+out:
+       if (dmt)
+               dm_task_destroy(dmt);
 
-/*
- * Set uuid to NULL for root of tree.
- */
-struct dm_tree_node *dm_tree_find_node_by_uuid(struct dm_tree *dtree,
-                                                 const char *uuid)
-{
-       if (!uuid || !*uuid)
-               return &dtree->root;
+       if (deps_dmt)
+               dm_task_destroy(deps_dmt);
 
-       return _find_dm_tree_node_by_uuid(dtree, uuid);
+       return r;
 }
 
-/*
- * First time set *handle to NULL.
- * Set inverted to invert the tree.
- */
-struct dm_tree_node *dm_tree_next_child(void **handle,
-                                       const struct dm_tree_node *parent,
-                                       uint32_t inverted)
+struct dm_tree_node *dm_tree_add_new_dev_with_udev_flags(struct dm_tree *dtree,
+                                                        const char *name,
+                                                        const char *uuid,
+                                                        uint32_t major,
+                                                        uint32_t minor,
+                                                        int read_only,
+                                                        int clear_inactive,
+                                                        void *context,
+                                                        uint16_t udev_flags)
 {
-       struct dm_list **dlink = (struct dm_list **) handle;
-       const struct dm_list *use_list;
-
-       if (inverted)
-               use_list = &parent->used_by;
-       else
-               use_list = &parent->uses;
+       struct dm_tree_node *dnode;
+       struct dm_info info = { 0 };
+       const char *name2;
+       const char *uuid2;
 
-       if (!*dlink)
-               *dlink = dm_list_first(use_list);
-       else
-               *dlink = dm_list_next(use_list, *dlink);
+       if (!name || !uuid) {
+               log_error("Cannot add device without name and uuid.");
+               return NULL;
+       }
 
-       return (*dlink) ? dm_list_item(*dlink, struct dm_tree_link)->node : NULL;
-}
+       /* Do we need to add node to tree? */
+       if (!(dnode = dm_tree_find_node_by_uuid(dtree, uuid))) {
+               if (!(name2 = dm_pool_strdup(dtree->mem, name))) {
+                       log_error("name pool_strdup failed");
+                       return NULL;
+               }
+               if (!(uuid2 = dm_pool_strdup(dtree->mem, uuid))) {
+                       log_error("uuid pool_strdup failed");
+                       return NULL;
+               }
 
-/*
- * Deactivate a device with its dependencies if the uuid prefix matches.
- */
-static int _info_by_dev(uint32_t major, uint32_t minor, int with_open_count,
-                       struct dm_info *info)
-{
-       struct dm_task *dmt;
-       int r;
+               if (!(dnode = _create_dm_tree_node(dtree, name2, uuid2, &info,
+                                                  context, 0)))
+                       return_NULL;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
-               log_error("_info_by_dev: dm_task creation failed");
-               return 0;
-       }
+               /* Attach to root node until a table is supplied */
+               if (!_add_to_toplevel(dnode) || !_add_to_bottomlevel(dnode))
+                       return_NULL;
 
-       if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
-               log_error("_info_by_dev: Failed to set device number");
-               dm_task_destroy(dmt);
-               return 0;
+               dnode->props.major = major;
+               dnode->props.minor = minor;
+               dnode->props.new_name = NULL;
+               dnode->props.size_changed = 0;
+       } else if (strcmp(name, dnode->name)) {
+               /* Do we need to rename node? */
+               if (!(dnode->props.new_name = dm_pool_strdup(dtree->mem, name))) {
+                       log_error("name pool_strdup failed");
+                       return NULL;
+               }
        }
 
-       if (!with_open_count && !dm_task_no_open_count(dmt))
-               log_error("Failed to disable open_count");
+       dnode->props.read_only = read_only ? 1 : 0;
+       dnode->props.read_ahead = DM_READ_AHEAD_AUTO;
+       dnode->props.read_ahead_flags = 0;
 
-       if ((r = dm_task_run(dmt)))
-               r = dm_task_get_info(dmt, info);
+       if (clear_inactive && !_node_clear_table(dnode, udev_flags))
+               return_NULL;
 
-       dm_task_destroy(dmt);
+       dnode->context = context;
+       dnode->udev_flags = udev_flags;
 
-       return r;
+       return dnode;
 }
 
-/* Check if all parent nodes of given node have open_count == 0 */
-static int _node_has_closed_parents(struct dm_tree_node *node,
-                                   const char *uuid_prefix,
-                                   size_t uuid_prefix_len)
+struct dm_tree_node *dm_tree_add_new_dev(struct dm_tree *dtree, const char *name,
+                                        const char *uuid, uint32_t major, uint32_t minor,
+                                        int read_only, int clear_inactive, void *context)
 {
-       struct dm_tree_link *dlink;
-       const struct dm_info *dinfo;
-       struct dm_info info;
-       const char *uuid;
-
-       /* Iterate through parents of this node */
-       dm_list_iterate_items(dlink, &node->used_by) {
-               if (!(uuid = dm_tree_node_get_uuid(dlink->node))) {
-                       stack;
-                       continue;
-               }
-
-               /* Ignore if it doesn't belong to this VG */
-               if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
-                       continue;
-
-               if (!(dinfo = dm_tree_node_get_info(dlink->node))) {
-                       stack;  /* FIXME Is this normal? */
-                       return 0;
-               }
-
-               /* Refresh open_count */
-               if (!_info_by_dev(dinfo->major, dinfo->minor, 1, &info) ||
-                   !info.exists)
-                       continue;
-
-               if (info.open_count)
-                       return 0;
-       }
-
-       return 1;
+       return dm_tree_add_new_dev_with_udev_flags(dtree, name, uuid, major, minor,
+                                                  read_only, clear_inactive, context, 0);
 }
 
-static int _deactivate_node(const char *name, uint32_t major, uint32_t minor,
-                           uint32_t *cookie, uint16_t udev_flags)
+static struct dm_tree_node *_add_dev(struct dm_tree *dtree,
+                                    struct dm_tree_node *parent,
+                                    uint32_t major, uint32_t minor,
+                                    uint16_t udev_flags)
 {
-       struct dm_task *dmt;
-       int r = 0;
+       struct dm_task *dmt = NULL;
+       struct dm_info info;
+       struct dm_deps *deps = NULL;
+       const char *name = NULL;
+       const char *uuid = NULL;
+       struct dm_tree_node *node = NULL;
+       uint32_t i;
+       int new = 0;
 
-       log_verbose("Removing %s (%" PRIu32 ":%" PRIu32 ")", name, major, minor);
+       /* Already in tree? */
+       if (!(node = _find_dm_tree_node(dtree, major, minor))) {
+               if (!_deps(&dmt, dtree->mem, major, minor, &name, &uuid, 0, &info, &deps))
+                       return_NULL;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_REMOVE))) {
-               log_error("Deactivation dm_task creation failed for %s", name);
-               return 0;
+               if (!(node = _create_dm_tree_node(dtree, name, uuid, &info,
+                                                 NULL, udev_flags)))
+                       goto_out;
+               new = 1;
        }
 
-       if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
-               log_error("Failed to set device number for %s deactivation", name);
-               goto out;
+       if (!_link_tree_nodes(parent, node)) {
+               node = NULL;
+               goto_out;
        }
 
-       if (!dm_task_no_open_count(dmt))
-               log_error("Failed to disable open_count");
+       /* If node was already in tree, no need to recurse. */
+       if (!new)
+               goto out;
 
-       if (!dm_task_set_cookie(dmt, cookie, udev_flags))
+       /* Can't recurse if not a mapped device or there are no dependencies */
+       if (!node->info.exists || !deps || !deps->count) {
+               if (!_add_to_bottomlevel(node)) {
+                       stack;
+                       node = NULL;
+               }
                goto out;
+       }
 
-       r = dm_task_run(dmt);
+       /* Add dependencies to tree */
+       for (i = 0; i < deps->count; i++)
+               if (!_add_dev(dtree, node, MAJOR(deps->device[i]),
+                             MINOR(deps->device[i]), udev_flags)) {
+                       node = NULL;
+                       goto_out;
+               }
 
-       /* FIXME Until kernel returns actual name so dm-ioctl.c can handle it */
-       rm_dev_node(name, dmt->cookie_set &&
-                         !(udev_flags & DM_UDEV_DISABLE_DM_RULES_FLAG));
+out:
+       if (dmt)
+               dm_task_destroy(dmt);
 
-       /* FIXME Remove node from tree or mark invalid? */
+       return node;
+}
 
-out:
-       dm_task_destroy(dmt);
+int dm_tree_add_dev(struct dm_tree *dtree, uint32_t major, uint32_t minor)
+{
+       return _add_dev(dtree, &dtree->root, major, minor, 0) ? 1 : 0;
+}
 
-       return r;
+int dm_tree_add_dev_with_udev_flags(struct dm_tree *dtree, uint32_t major,
+                                   uint32_t minor, uint16_t udev_flags)
+{
+       return _add_dev(dtree, &dtree->root, major, minor, udev_flags) ? 1 : 0;
 }
 
 static int _rename_node(const char *old_name, const char *new_name, uint32_t major,
@@ -1002,7 +1235,7 @@ static int _rename_node(const char *old_name, const char *new_name, uint32_t maj
        }
 
        if (!dm_task_set_newname(dmt, new_name))
-                goto_out;
+               goto_out;
 
        if (!dm_task_no_open_count(dmt))
                log_error("Failed to disable open_count");
@@ -1022,7 +1255,7 @@ out:
 static int _resume_node(const char *name, uint32_t major, uint32_t minor,
                        uint32_t read_ahead, uint32_t read_ahead_flags,
                        struct dm_info *newinfo, uint32_t *cookie,
-                       uint16_t udev_flags)
+                       uint16_t udev_flags, int already_suspended)
 {
        struct dm_task *dmt;
        int r = 0;
@@ -1030,13 +1263,13 @@ static int _resume_node(const char *name, uint32_t major, uint32_t minor,
        log_verbose("Resuming %s (%" PRIu32 ":%" PRIu32 ")", name, major, minor);
 
        if (!(dmt = dm_task_create(DM_DEVICE_RESUME))) {
-               log_error("Suspend dm_task creation failed for %s", name);
+               log_debug("Suspend dm_task creation failed for %s.", name);
                return 0;
        }
 
        /* FIXME Kernel should fill in name on return instead */
        if (!dm_task_set_name(dmt, name)) {
-               log_error("Failed to set readahead device name for %s", name);
+               log_debug("Failed to set device name for %s resumption.", name);
                goto out;
        }
 
@@ -1052,10 +1285,16 @@ static int _resume_node(const char *name, uint32_t major, uint32_t minor,
                log_error("Failed to set read ahead");
 
        if (!dm_task_set_cookie(dmt, cookie, udev_flags))
-               goto out;
+               goto_out;
 
-       if ((r = dm_task_run(dmt)))
-               r = dm_task_get_info(dmt, newinfo);
+       if (!(r = dm_task_run(dmt)))
+               goto_out;
+
+       if (already_suspended)
+               dec_suspended();
+
+       if (!(r = dm_task_get_info(dmt, newinfo)))
+               stack;
 
 out:
        dm_task_destroy(dmt);
@@ -1094,14 +1333,176 @@ static int _suspend_node(const char *name, uint32_t major, uint32_t minor,
        if (no_flush && !dm_task_no_flush(dmt))
                log_error("Failed to set no_flush flag.");
 
-       if ((r = dm_task_run(dmt)))
+       if ((r = dm_task_run(dmt))) {
+               inc_suspended();
                r = dm_task_get_info(dmt, newinfo);
+       }
+
+       dm_task_destroy(dmt);
 
+       return r;
+}
+
+static int _thin_pool_status_transaction_id(struct dm_tree_node *dnode, uint64_t *transaction_id)
+{
+       struct dm_task *dmt;
+       int r = 0;
+       uint64_t start, length;
+       char *type = NULL;
+       char *params = NULL;
+
+       if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
+               return_0;
+
+       if (!dm_task_set_major(dmt, dnode->info.major) ||
+           !dm_task_set_minor(dmt, dnode->info.minor)) {
+               log_error("Failed to set major minor.");
+               goto out;
+       }
+
+       if (!dm_task_run(dmt))
+               goto_out;
+
+       dm_get_next_target(dmt, NULL, &start, &length, &type, &params);
+
+       if (type && (strcmp(type, "thin-pool") != 0)) {
+               log_error("Expected thin-pool target for %d:%d and got %s.",
+                         dnode->info.major, dnode->info.minor, type);
+               goto out;
+       }
+
+       if (!params || (sscanf(params, "%" PRIu64, transaction_id) != 1)) {
+               log_error("Failed to parse transaction_id from %s.", params);
+               goto out;
+       }
+
+       log_debug("Thin pool transaction id: %" PRIu64 " status: %s.", *transaction_id, params);
+
+       r = 1;
+out:
+       dm_task_destroy(dmt);
+
+       return r;
+}
+
+static int _thin_pool_node_message(struct dm_tree_node *dnode, struct thin_message *tm)
+{
+       struct dm_task *dmt;
+       struct dm_thin_message *m = &tm->message;
+       char buf[64];
+       int r;
+
+       switch (m->type) {
+       case DM_THIN_MESSAGE_CREATE_SNAP:
+               r = dm_snprintf(buf, sizeof(buf), "create_snap %u %u",
+                               m->u.m_create_snap.device_id,
+                               m->u.m_create_snap.origin_id);
+               break;
+       case DM_THIN_MESSAGE_CREATE_THIN:
+               r = dm_snprintf(buf, sizeof(buf), "create_thin %u",
+                               m->u.m_create_thin.device_id);
+               break;
+       case DM_THIN_MESSAGE_DELETE:
+               r = dm_snprintf(buf, sizeof(buf), "delete %u",
+                               m->u.m_delete.device_id);
+               break;
+       case DM_THIN_MESSAGE_SET_TRANSACTION_ID:
+               r = dm_snprintf(buf, sizeof(buf),
+                               "set_transaction_id %" PRIu64 " %" PRIu64,
+                               m->u.m_set_transaction_id.current_id,
+                               m->u.m_set_transaction_id.new_id);
+               break;
+       case DM_THIN_MESSAGE_RESERVE_METADATA_SNAP: /* target vsn 1.1 */
+               r = dm_snprintf(buf, sizeof(buf), "reserve_metadata_snap");
+               break;
+       case DM_THIN_MESSAGE_RELEASE_METADATA_SNAP: /* target vsn 1.1 */
+               r = dm_snprintf(buf, sizeof(buf), "release_metadata_snap");
+               break;
+       default:
+               r = -1;
+       }
+
+       if (r < 0) {
+               log_error("Failed to prepare message.");
+               return 0;
+       }
+
+       r = 0;
+
+       if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
+               return_0;
+
+       if (!dm_task_set_major(dmt, dnode->info.major) ||
+           !dm_task_set_minor(dmt, dnode->info.minor)) {
+               log_error("Failed to set message major minor.");
+               goto out;
+       }
+
+       if (!dm_task_set_message(dmt, buf))
+               goto_out;
+
+        /* Internal functionality of dm_task */
+       dmt->expected_errno = tm->expected_errno;
+
+       if (!dm_task_run(dmt))
+               goto_out;
+
+       r = 1;
+out:
        dm_task_destroy(dmt);
 
        return r;
 }
 
+static int _node_send_messages(struct dm_tree_node *dnode,
+                              const char *uuid_prefix,
+                              size_t uuid_prefix_len)
+{
+       struct load_segment *seg;
+       struct thin_message *tmsg;
+       uint64_t trans_id;
+       const char *uuid;
+
+       if (!dnode->info.exists || (dm_list_size(&dnode->props.segs) != 1))
+               return 1;
+
+       seg = dm_list_item(dm_list_last(&dnode->props.segs), struct load_segment);
+       if (seg->type != SEG_THIN_POOL)
+               return 1;
+
+       if (!(uuid = dm_tree_node_get_uuid(dnode)))
+               return_0;
+
+       if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len)) {
+               log_debug("UUID \"%s\" does not match.", uuid);
+               return 1;
+       }
+
+       if (!_thin_pool_status_transaction_id(dnode, &trans_id))
+               goto_bad;
+
+       if (trans_id == seg->transaction_id)
+               return 1; /* In sync - skip messages */
+
+       if (trans_id != (seg->transaction_id - 1)) {
+               log_error("Thin pool transaction_id=%" PRIu64 ", while expected: %" PRIu64 ".",
+                         trans_id, seg->transaction_id - 1);
+               goto bad; /* Nothing to send */
+       }
+
+       dm_list_iterate_items(tmsg, &seg->thin_messages)
+               if (!(_thin_pool_node_message(dnode, tmsg)))
+                       goto_bad;
+
+       return 1;
+bad:
+       /* Try to deactivate */
+       if (!(dm_tree_deactivate_children(dnode, uuid_prefix, uuid_prefix_len)))
+               log_error("Failed to deactivate %s", dnode->name);
+
+       return 0;
+}
+
 /*
  * FIXME Don't attempt to deactivate known internal dependencies.
  */
@@ -1139,13 +1540,34 @@ static int _dm_tree_deactivate_children(struct dm_tree_node *dnode,
                        continue;
 
                /* Refresh open_count */
-               if (!_info_by_dev(dinfo->major, dinfo->minor, 1, &info) ||
+               if (!_info_by_dev(dinfo->major, dinfo->minor, 1, &info, NULL, NULL, NULL) ||
                    !info.exists)
                        continue;
 
+               if (info.open_count) {
+                       /* Skip internal non-toplevel opened nodes */
+                       if (level)
+                               continue;
+
+                       /* When retry is not allowed, error */
+                       if (!child->dtree->retry_remove) {
+                               log_error("Unable to deactivate open %s (%" PRIu32
+                                         ":%" PRIu32 ")", name, info.major, info.minor);
+                               r = 0;
+                               continue;
+                       }
+
+                       /* Check toplevel node for holders/mounted fs */
+                       if (!_check_device_not_in_use(name, &info)) {
+                               stack;
+                               r = 0;
+                               continue;
+                       }
+                       /* Go on with retry */
+               }
+
                /* Also checking open_count in parent nodes of presuspend_node */
-               if (info.open_count ||
-                   (child->presuspend_node &&
+               if ((child->presuspend_node &&
                     !_node_has_closed_parents(child->presuspend_node,
                                               uuid_prefix, uuid_prefix_len))) {
                        /* Only report error from (likely non-internal) dependency at top level */
@@ -1164,18 +1586,27 @@ static int _dm_tree_deactivate_children(struct dm_tree_node *dnode,
                        continue;
 
                if (!_deactivate_node(name, info.major, info.minor,
-                                     &child->dtree->cookie, child->udev_flags)) {
+                                     &child->dtree->cookie, child->udev_flags,
+                                     (level == 0) ? child->dtree->retry_remove : 0)) {
                        log_error("Unable to deactivate %s (%" PRIu32
                                  ":%" PRIu32 ")", name, info.major,
                                  info.minor);
                        r = 0;
                        continue;
-               }
+               } else if (info.suspended)
+                       dec_suspended();
 
-               if (dm_tree_node_num_children(child, 0)) {
-                       if (!_dm_tree_deactivate_children(child, uuid_prefix, uuid_prefix_len, level + 1))
-                               return_0;
-               }
+               if (child->callback &&
+                   !child->callback(child, DM_NODE_CALLBACK_DEACTIVATED,
+                                    child->callback_data))
+                       stack;
+                       // FIXME: We need to let lvremove pass,
+                       // so for now deactivation ignores check result
+                       //r = 0; // FIXME: _node_clear_table() without callback ?
+
+               if (dm_tree_node_num_children(child, 0) &&
+                   !_dm_tree_deactivate_children(child, uuid_prefix, uuid_prefix_len, level + 1))
+                       return_0;
        }
 
        return r;
@@ -1188,16 +1619,6 @@ int dm_tree_deactivate_children(struct dm_tree_node *dnode,
        return _dm_tree_deactivate_children(dnode, uuid_prefix, uuid_prefix_len, 0);
 }
 
-void dm_tree_skip_lockfs(struct dm_tree_node *dnode)
-{
-       dnode->dtree->skip_lockfs = 1;
-}
-
-void dm_tree_use_no_flush_suspend(struct dm_tree_node *dnode)
-{
-       dnode->dtree->no_flush = 1;
-}
-
 int dm_tree_suspend_children(struct dm_tree_node *dnode,
                             const char *uuid_prefix,
                             size_t uuid_prefix_len)
@@ -1235,7 +1656,7 @@ int dm_tree_suspend_children(struct dm_tree_node *dnode,
                if (!_children_suspended(child, 1, uuid_prefix, uuid_prefix_len))
                        continue;
 
-               if (!_info_by_dev(dinfo->major, dinfo->minor, 0, &info) ||
+               if (!_info_by_dev(dinfo->major, dinfo->minor, 0, &info, NULL, NULL, NULL) ||
                    !info.exists || info.suspended)
                        continue;
 
@@ -1305,6 +1726,9 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
 
        for (priority = 0; priority < 3; priority++) {
                while ((child = dm_tree_next_child(&handle, dnode, 0))) {
+                       if (priority != child->activation_priority)
+                               continue;
+
                        if (!(uuid = dm_tree_node_get_uuid(child))) {
                                stack;
                                continue;
@@ -1313,9 +1737,6 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
                        if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
                                continue;
 
-                       if (priority != child->activation_priority)
-                               continue;
-
                        if (!(name = dm_tree_node_get_name(child))) {
                                stack;
                                continue;
@@ -1340,7 +1761,7 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
 
                        if (!_resume_node(child->name, child->info.major, child->info.minor,
                                          child->props.read_ahead, child->props.read_ahead_flags,
-                                         &newinfo, &child->dtree->cookie, child->udev_flags)) {
+                                         &newinfo, &child->dtree->cookie, child->udev_flags, child->info.suspended)) {
                                log_error("Unable to resume %s (%" PRIu32
                                          ":%" PRIu32 ")", child->name, child->info.major,
                                          child->info.minor);
@@ -1353,6 +1774,17 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
                }
        }
 
+       /*
+        * FIXME: Implement delayed error reporting
+        * activation should be stopped only in the case,
+        * the submission of transation_id message fails,
+        * resume should continue further, just whole command
+        * has to report failure.
+        */
+       if (r && dnode->props.send_messages &&
+           !(r = _node_send_messages(dnode, uuid_prefix, uuid_prefix_len)))
+               stack;
+
        handle = NULL;
 
        return r;
@@ -1408,10 +1840,10 @@ out:
 static int _build_dev_string(char *devbuf, size_t bufsize, struct dm_tree_node *node)
 {
        if (!dm_format_dev(devbuf, bufsize, node->info.major, node->info.minor)) {
-                log_error("Failed to format %s device number for %s as dm "
-                          "target (%u,%u)",
-                          node->name, node->uuid, node->info.major, node->info.minor);
-                return 0;
+               log_error("Failed to format %s device number for %s as dm "
+                         "target (%u,%u)",
+                         node->name, node->uuid, node->info.major, node->info.minor);
+               return 0;
        }
 
        return 1;
@@ -1444,11 +1876,11 @@ static int _emit_areas_line(struct dm_task *dmt __attribute__((unused)),
        unsigned log_parm_count;
 
        dm_list_iterate_items(area, &seg->areas) {
-               if (!_build_dev_string(devbuf, sizeof(devbuf), area->dev_node))
-                       return_0;
-
                switch (seg->type) {
                case SEG_REPLICATOR_DEV:
+                       if (!_build_dev_string(devbuf, sizeof(devbuf), area->dev_node))
+                               return_0;
+
                        EMIT_PARAMS(*pos, " %d 1 %s", area->rsite_index, devbuf);
                        if (first_time)
                                EMIT_PARAMS(*pos, " nolog 0");
@@ -1481,7 +1913,29 @@ static int _emit_areas_line(struct dm_task *dmt __attribute__((unused)),
                                        EMIT_PARAMS(*pos, "%s", synctype);
                        }
                        break;
+               case SEG_RAID1:
+               case SEG_RAID10:
+               case SEG_RAID4:
+               case SEG_RAID5_LA:
+               case SEG_RAID5_RA:
+               case SEG_RAID5_LS:
+               case SEG_RAID5_RS:
+               case SEG_RAID6_ZR:
+               case SEG_RAID6_NR:
+               case SEG_RAID6_NC:
+                       if (!area->dev_node) {
+                               EMIT_PARAMS(*pos, " -");
+                               break;
+                       }
+                       if (!_build_dev_string(devbuf, sizeof(devbuf), area->dev_node))
+                               return_0;
+
+                       EMIT_PARAMS(*pos, " %s", devbuf);
+                       break;
                default:
+                       if (!_build_dev_string(devbuf, sizeof(devbuf), area->dev_node))
+                               return_0;
+
                        EMIT_PARAMS(*pos, "%s%s %" PRIu64, first_time ? "" : " ",
                                    devbuf, area->offset);
                }
@@ -1531,23 +1985,28 @@ static int _replicator_emit_segment_line(const struct load_segment *seg, char *p
 /*
  * Returns: 1 on success, 0 on failure
  */
-static int _mirror_emit_segment_line(struct dm_task *dmt, uint32_t major,
-                                    uint32_t minor, struct load_segment *seg,
-                                    uint64_t *seg_start, char *params,
-                                    size_t paramsize)
+static int _mirror_emit_segment_line(struct dm_task *dmt, struct load_segment *seg,
+                                    char *params, size_t paramsize)
 {
        int block_on_error = 0;
        int handle_errors = 0;
        int dm_log_userspace = 0;
        struct utsname uts;
        unsigned log_parm_count;
-       int pos = 0;
+       int pos = 0, parts;
        char logbuf[DM_FORMAT_DEV_BUFSIZE];
        const char *logtype;
-       unsigned kmaj, kmin, krel;
+       unsigned kmaj = 0, kmin = 0, krel = 0;
+
+       if (uname(&uts) == -1) {
+               log_error("Cannot read kernel release version.");
+               return 0;
+       }
 
-       if (uname(&uts) == -1 || sscanf(uts.release, "%u.%u.%u", &kmaj, &kmin, &krel) != 3) {
-               log_error("Cannot read kernel release version");
+       /* Kernels with a major number of 2 always had 3 parts. */
+       parts = sscanf(uts.release, "%u.%u.%u", &kmaj, &kmin, &krel);
+       if (parts < 1 || (kmaj < 3 && parts < 3)) {
+               log_error("Wrong kernel release version %s.", uts.release);
                return 0;
        }
 
@@ -1651,6 +2110,103 @@ static int _mirror_emit_segment_line(struct dm_task *dmt, uint32_t major,
        return 1;
 }
 
+static int _raid_emit_segment_line(struct dm_task *dmt, uint32_t major,
+                                  uint32_t minor, struct load_segment *seg,
+                                  uint64_t *seg_start, char *params,
+                                  size_t paramsize)
+{
+       uint32_t i;
+       int param_count = 1; /* mandatory 'chunk size'/'stripe size' arg */
+       int pos = 0;
+
+       if ((seg->flags & DM_NOSYNC) || (seg->flags & DM_FORCESYNC))
+               param_count++;
+
+       if (seg->region_size)
+               param_count += 2;
+
+       /* rebuilds is 64-bit */
+       param_count += 2 * hweight32(seg->rebuilds & 0xFFFFFFFF);
+       param_count += 2 * hweight32(seg->rebuilds >> 32);
+
+       if ((seg->type == SEG_RAID1) && seg->stripe_size)
+               log_error("WARNING: Ignoring RAID1 stripe size");
+
+       EMIT_PARAMS(pos, "%s %d %u", dm_segtypes[seg->type].target,
+                   param_count, seg->stripe_size);
+
+       if (seg->flags & DM_NOSYNC)
+               EMIT_PARAMS(pos, " nosync");
+       else if (seg->flags & DM_FORCESYNC)
+               EMIT_PARAMS(pos, " sync");
+
+       if (seg->region_size)
+               EMIT_PARAMS(pos, " region_size %u", seg->region_size);
+
+       for (i = 0; i < (seg->area_count / 2); i++)
+               if (seg->rebuilds & (1 << i))
+                       EMIT_PARAMS(pos, " rebuild %u", i);
+
+       /* Print number of metadata/data device pairs */
+       EMIT_PARAMS(pos, " %u", seg->area_count/2);
+
+       if (_emit_areas_line(dmt, seg, params, paramsize, &pos) <= 0)
+               return_0;
+
+       return 1;
+}
+
+static int _thin_pool_emit_segment_line(struct dm_task *dmt,
+                                       struct load_segment *seg,
+                                       char *params, size_t paramsize)
+{
+       int pos = 0;
+       char pool[DM_FORMAT_DEV_BUFSIZE], metadata[DM_FORMAT_DEV_BUFSIZE];
+       int features = (seg->skip_block_zeroing ? 1 : 0) +
+                       (seg->ignore_discard ? 1 : 0) +
+                       (seg->no_discard_passdown ? 1 : 0);
+
+       if (!_build_dev_string(metadata, sizeof(metadata), seg->metadata))
+               return_0;
+
+       if (!_build_dev_string(pool, sizeof(pool), seg->pool))
+               return_0;
+
+       EMIT_PARAMS(pos, "%s %s %d %" PRIu64 " %d%s%s%s", metadata, pool,
+                   seg->data_block_size, seg->low_water_mark, features,
+                   seg->skip_block_zeroing ? " skip_block_zeroing" : "",
+                   seg->ignore_discard ? " ignore_discard" : "",
+                   seg->no_discard_passdown ? " no_discard_passdown" : ""
+                  );
+
+       return 1;
+}
+
+static int _thin_emit_segment_line(struct dm_task *dmt,
+                                  struct load_segment *seg,
+                                  char *params, size_t paramsize)
+{
+       int pos = 0;
+       char pool[DM_FORMAT_DEV_BUFSIZE];
+       char external[DM_FORMAT_DEV_BUFSIZE + 1];
+
+       if (!_build_dev_string(pool, sizeof(pool), seg->pool))
+               return_0;
+
+       if (!seg->external)
+               *external = 0;
+       else {
+               *external = ' ';
+               if (!_build_dev_string(external + 1, sizeof(external) - 1,
+                                      seg->external))
+                       return_0;
+       }
+
+       EMIT_PARAMS(pos, "%s %d%s", pool, seg->device_id, external);
+
+       return 1;
+}
+
 static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
                              uint32_t minor, struct load_segment *seg,
                              uint64_t *seg_start, char *params,
@@ -1658,6 +2214,7 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
 {
        int pos = 0;
        int r;
+       int target_type_is_raid = 0;
        char originbuf[DM_FORMAT_DEV_BUFSIZE], cowbuf[DM_FORMAT_DEV_BUFSIZE];
 
        switch(seg->type) {
@@ -1667,8 +2224,7 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
                break;
        case SEG_MIRRORED:
                /* Mirrors are pretty complicated - now in separate function */
-               r = _mirror_emit_segment_line(dmt, major, minor, seg, seg_start,
-                                             params, paramsize);
+               r = _mirror_emit_segment_line(dmt, seg, params, paramsize);
                if (!r)
                        return_0;
                break;
@@ -1711,6 +2267,31 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
                            seg->iv_offset != DM_CRYPT_IV_DEFAULT ?
                            seg->iv_offset : *seg_start);
                break;
+       case SEG_RAID1:
+       case SEG_RAID10:
+       case SEG_RAID4:
+       case SEG_RAID5_LA:
+       case SEG_RAID5_RA:
+       case SEG_RAID5_LS:
+       case SEG_RAID5_RS:
+       case SEG_RAID6_ZR:
+       case SEG_RAID6_NR:
+       case SEG_RAID6_NC:
+               target_type_is_raid = 1;
+               r = _raid_emit_segment_line(dmt, major, minor, seg, seg_start,
+                                           params, paramsize);
+               if (!r)
+                       return_0;
+
+               break;
+       case SEG_THIN_POOL:
+               if (!_thin_pool_emit_segment_line(dmt, seg, params, paramsize))
+                       return_0;
+               break;
+       case SEG_THIN:
+               if (!_thin_emit_segment_line(dmt, seg, params, paramsize))
+                       return_0;
+               break;
        }
 
        switch(seg->type) {
@@ -1720,6 +2301,8 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
        case SEG_SNAPSHOT_ORIGIN:
        case SEG_SNAPSHOT_MERGE:
        case SEG_ZERO:
+       case SEG_THIN_POOL:
+       case SEG_THIN:
                break;
        case SEG_CRYPT:
        case SEG_LINEAR:
@@ -1729,14 +2312,23 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
                        stack;
                        return r;
                }
+               if (!params[0]) {
+                       log_error("No parameters supplied for %s target "
+                                 "%u:%u.", dm_segtypes[seg->type].target,
+                                 major, minor);
+                       return 0;
+               }
                break;
        }
 
        log_debug("Adding target to (%" PRIu32 ":%" PRIu32 "): %" PRIu64
                  " %" PRIu64 " %s %s", major, minor,
-                 *seg_start, seg->size, dm_segtypes[seg->type].target, params);
+                 *seg_start, seg->size, target_type_is_raid ? "raid" :
+                 dm_segtypes[seg->type].target, params);
 
-       if (!dm_task_add_target(dmt, *seg_start, seg->size, dm_segtypes[seg->type].target, params))
+       if (!dm_task_add_target(dmt, *seg_start, seg->size,
+                               target_type_is_raid ? "raid" :
+                               dm_segtypes[seg->type].target, params))
                return_0;
 
        *seg_start += seg->size;
@@ -1785,7 +2377,7 @@ static int _load_node(struct dm_tree_node *dnode)
        int r = 0;
        struct dm_task *dmt;
        struct load_segment *seg;
-       uint64_t seg_start = 0;
+       uint64_t seg_start = 0, existing_table_size;
 
        log_verbose("Loading %s table (%" PRIu32 ":%" PRIu32 ")", dnode->name,
                    dnode->info.major, dnode->info.minor);
@@ -1820,15 +2412,28 @@ static int _load_node(struct dm_tree_node *dnode)
        if ((r = dm_task_run(dmt))) {
                r = dm_task_get_info(dmt, &dnode->info);
                if (r && !dnode->info.inactive_table)
-                       log_verbose("Suppressed %s identical table reload.",
-                                   dnode->name);
+                       log_verbose("Suppressed %s (%" PRIu32 ":%" PRIu32
+                                   ") identical table reload.",
+                                   dnode->name,
+                                   dnode->info.major, dnode->info.minor);
 
+               existing_table_size = dm_task_get_existing_table_size(dmt);
                if ((dnode->props.size_changed =
-                    (dm_task_get_existing_table_size(dmt) == seg_start) ? 0 : 1))
+                    (existing_table_size == seg_start) ? 0 : 1)) {
+                       /*
+                        * Kernel usually skips size validation on zero-length devices
+                        * now so no need to preload them.
+                        */
+                       /* FIXME In which kernel version did this begin? */
+                       if (!existing_table_size && dnode->props.delay_resume_if_new)
+                               dnode->props.size_changed = 0;
+
                        log_debug("Table size changed from %" PRIu64 " to %"
-                                 PRIu64 " for %s",
-                                 dm_task_get_existing_table_size(dmt),
-                                 seg_start, dnode->name);
+                                 PRIu64 " for %s (%" PRIu32 ":%" PRIu32 ").%s",
+                                 existing_table_size, seg_start, dnode->name,
+                                 dnode->info.major, dnode->info.minor,
+                                 dnode->props.size_changed ? "" : " (Ignoring.)");
+               }
        }
 
        dnode->props.segment_count = 0;
@@ -1865,19 +2470,13 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
                                return_0;
 
                /* FIXME Cope if name exists with no uuid? */
-               if (!child->info.exists) {
-                       if (!_create_node(child)) {
-                               stack;
-                               return 0;
-                       }
-               }
+               if (!child->info.exists && !_create_node(child))
+                       return_0;
 
-               if (!child->info.inactive_table && child->props.segment_count) {
-                       if (!_load_node(child)) {
-                               stack;
-                               return 0;
-                       }
-               }
+               if (!child->info.inactive_table &&
+                   child->props.segment_count &&
+                   !_load_node(child))
+                       return_0;
 
                /* Propagate device size change change */
                if (child->props.size_changed)
@@ -1892,7 +2491,8 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
 
                if (!_resume_node(child->name, child->info.major, child->info.minor,
                                  child->props.read_ahead, child->props.read_ahead_flags,
-                                 &newinfo, &child->dtree->cookie, child->udev_flags)) {
+                                 &newinfo, &child->dtree->cookie, child->udev_flags,
+                                 child->info.suspended)) {
                        log_error("Unable to resume %s (%" PRIu32
                                  ":%" PRIu32 ")", child->name, child->info.major,
                                  child->info.minor);
@@ -1902,7 +2502,6 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
 
                /* Update cached info */
                child->info = newinfo;
-
                /*
                 * Prepare for immediate synchronization with udev and flush all stacked
                 * dev node operations if requested by immediate_dev_node property. But
@@ -1910,16 +2509,18 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
                 */
                if (child->props.immediate_dev_node)
                        update_devs_flag = 1;
-
        }
 
-       handle = NULL;
-
-       if (update_devs_flag) {
+       if (update_devs_flag ||
+           (!dnode->info.exists && dnode->callback)) {
                if (!dm_udev_wait(dm_tree_get_cookie(dnode)))
                        stack;
                dm_tree_set_cookie(dnode, 0);
-               dm_task_update_nodes();
+
+               if (!dnode->info.exists && dnode->callback &&
+                   !dnode->callback(child, DM_NODE_CALLBACK_PRELOADED,
+                                    dnode->callback_data))
+                       return_0;
        }
 
        return r;
@@ -1982,8 +2583,8 @@ static struct load_segment *_add_segment(struct dm_tree_node *dnode, unsigned ty
 }
 
 int dm_tree_node_add_snapshot_origin_target(struct dm_tree_node *dnode,
-                                               uint64_t size,
-                                               const char *origin_uuid)
+                                              uint64_t size,
+                                              const char *origin_uuid)
 {
        struct load_segment *seg;
        struct dm_tree_node *origin_node;
@@ -2003,6 +2604,12 @@ int dm_tree_node_add_snapshot_origin_target(struct dm_tree_node *dnode,
        /* Resume snapshot origins after new snapshots */
        dnode->activation_priority = 1;
 
+       /*
+        * Don't resume the origin immediately in case it is a non-trivial 
+        * target that must not be active more than once concurrently!
+        */
+       origin_node->props.delay_resume_if_new = 1;
+
        return 1;
 }
 
@@ -2088,7 +2695,7 @@ int dm_tree_node_add_snapshot_merge_target(struct dm_tree_node *node,
 }
 
 int dm_tree_node_add_error_target(struct dm_tree_node *node,
-                                     uint64_t size)
+                                    uint64_t size)
 {
        if (!_add_segment(node, SEG_ERROR, size))
                return_0;
@@ -2097,7 +2704,7 @@ int dm_tree_node_add_error_target(struct dm_tree_node *node,
 }
 
 int dm_tree_node_add_zero_target(struct dm_tree_node *node,
-                                    uint64_t size)
+                                   uint64_t size)
 {
        if (!_add_segment(node, SEG_ZERO, size))
                return_0;
@@ -2106,7 +2713,7 @@ int dm_tree_node_add_zero_target(struct dm_tree_node *node,
 }
 
 int dm_tree_node_add_linear_target(struct dm_tree_node *node,
-                                      uint64_t size)
+                                     uint64_t size)
 {
        if (!_add_segment(node, SEG_LINEAR, size))
                return_0;
@@ -2115,8 +2722,8 @@ int dm_tree_node_add_linear_target(struct dm_tree_node *node,
 }
 
 int dm_tree_node_add_striped_target(struct dm_tree_node *node,
-                                       uint64_t size,
-                                       uint32_t stripe_size)
+                                      uint64_t size,
+                                      uint32_t stripe_size)
 {
        struct load_segment *seg;
 
@@ -2172,7 +2779,10 @@ int dm_tree_node_add_mirror_target_log(struct dm_tree_node *node,
                        log_error("log uuid pool_strdup failed");
                        return 0;
                }
-               if (!(flags & DM_CORELOG)) {
+               if ((flags & DM_CORELOG))
+                       /* For pvmove: immediate resume (for size validation) isn't needed. */
+                       node->props.delay_resume_if_new = 1;
+               else {
                        if (!(log_node = dm_tree_find_node_by_uuid(node->dtree, log_uuid))) {
                                log_error("Couldn't find mirror log uuid %s.", log_uuid);
                                return 0;
@@ -2181,6 +2791,10 @@ int dm_tree_node_add_mirror_target_log(struct dm_tree_node *node,
                        if (clustered)
                                log_node->props.immediate_dev_node = 1;
 
+                       /* The kernel validates the size of disk logs. */
+                       /* FIXME Propagate to any devices below */
+                       log_node->props.delay_resume_if_new = 0;
+
                        if (!_link_tree_nodes(node, log_node))
                                return_0;
                }
@@ -2196,7 +2810,7 @@ int dm_tree_node_add_mirror_target_log(struct dm_tree_node *node,
 }
 
 int dm_tree_node_add_mirror_target(struct dm_tree_node *node,
-                                      uint64_t size)
+                                     uint64_t size)
 {
        if (!_add_segment(node, SEG_MIRRORED, size))
                return_0;
@@ -2204,6 +2818,35 @@ int dm_tree_node_add_mirror_target(struct dm_tree_node *node,
        return 1;
 }
 
+int dm_tree_node_add_raid_target(struct dm_tree_node *node,
+                                uint64_t size,
+                                const char *raid_type,
+                                uint32_t region_size,
+                                uint32_t stripe_size,
+                                uint64_t rebuilds,
+                                uint64_t flags)
+{
+       int i;
+       struct load_segment *seg = NULL;
+
+       for (i = 0; dm_segtypes[i].target && !seg; i++)
+               if (!strcmp(raid_type, dm_segtypes[i].target))
+                       if (!(seg = _add_segment(node,
+                                                dm_segtypes[i].type, size)))
+                               return_0;
+
+       if (!seg)
+               return_0;
+
+       seg->region_size = region_size;
+       seg->stripe_size = stripe_size;
+       seg->area_count = 0;
+       seg->rebuilds = rebuilds;
+       seg->flags = flags;
+
+       return 1;
+}
+
 int dm_tree_node_add_replicator_target(struct dm_tree_node *node,
                                       uint64_t size,
                                       const char *rlog_uuid,
@@ -2369,6 +3012,296 @@ int dm_tree_node_add_replicator_dev_target(struct dm_tree_node *node,
        return 1;
 }
 
+static struct load_segment *_get_single_load_segment(struct dm_tree_node *node,
+                                                    unsigned type)
+{
+       struct load_segment *seg;
+
+       if (node->props.segment_count != 1) {
+               log_error("Node %s must have only one segment.",
+                         dm_segtypes[type].target);
+               return NULL;
+       }
+
+       seg = dm_list_item(dm_list_last(&node->props.segs), struct load_segment);
+       if (seg->type != type) {
+               log_error("Node %s has segment type %s.",
+                         dm_segtypes[type].target,
+                         dm_segtypes[seg->type].target);
+               return NULL;
+       }
+
+       return seg;
+}
+
+static int _thin_validate_device_id(uint32_t device_id)
+{
+       if (device_id > DM_THIN_MAX_DEVICE_ID) {
+               log_error("Device id %u is higher then %u.",
+                         device_id, DM_THIN_MAX_DEVICE_ID);
+               return 0;
+       }
+
+       return 1;
+}
+
+int dm_tree_node_add_thin_pool_target(struct dm_tree_node *node,
+                                     uint64_t size,
+                                     uint64_t transaction_id,
+                                     const char *metadata_uuid,
+                                     const char *pool_uuid,
+                                     uint32_t data_block_size,
+                                     uint64_t low_water_mark,
+                                     unsigned skip_block_zeroing)
+{
+       struct load_segment *seg, *mseg;
+       uint64_t devsize = 0;
+       /*
+        * Max supported size for thin pool  metadata device
+        * Limitation is hardcoded into kernel and bigger
+        * device size is not accepted. (16978542592)
+        */
+       const uint64_t max_metadata_size =
+               255ULL * (1 << 14) * (4096 / (1 << 9)) - 256 * 1024;
+
+       if (data_block_size < DM_THIN_MIN_DATA_BLOCK_SIZE) {
+               log_error("Data block size %u is lower then %u sectors.",
+                         data_block_size, DM_THIN_MIN_DATA_BLOCK_SIZE);
+               return 0;
+       }
+
+       if (data_block_size > DM_THIN_MAX_DATA_BLOCK_SIZE) {
+               log_error("Data block size %u is higher then %u sectors.",
+                         data_block_size, DM_THIN_MAX_DATA_BLOCK_SIZE);
+               return 0;
+       }
+
+       if (!(seg = _add_segment(node, SEG_THIN_POOL, size)))
+               return_0;
+
+       if (!(seg->metadata = dm_tree_find_node_by_uuid(node->dtree, metadata_uuid))) {
+               log_error("Missing metadata uuid %s.", metadata_uuid);
+               return 0;
+       }
+
+       if (!_link_tree_nodes(node, seg->metadata))
+               return_0;
+
+       /* FIXME: more complex target may need more tweaks */
+       dm_list_iterate_items(mseg, &seg->metadata->props.segs) {
+               devsize += mseg->size;
+               if (devsize > max_metadata_size) {
+                       log_debug("Ignoring %" PRIu64 " of device.",
+                                 devsize - max_metadata_size);
+                       mseg->size -= (devsize - max_metadata_size);
+                       devsize = max_metadata_size;
+                       /* FIXME: drop remaining segs */
+               }
+       }
+
+       if (!(seg->pool = dm_tree_find_node_by_uuid(node->dtree, pool_uuid))) {
+               log_error("Missing pool uuid %s.", pool_uuid);
+               return 0;
+       }
+
+       if (!_link_tree_nodes(node, seg->pool))
+               return_0;
+
+       /* Clean flag delay_resume_if_new - so corelog gets resumed */
+       seg->metadata->props.delay_resume_if_new = 0;
+       seg->pool->props.delay_resume_if_new = 0;
+
+       node->props.send_messages = 1;
+       seg->transaction_id = transaction_id;
+       seg->low_water_mark = low_water_mark;
+       seg->data_block_size = data_block_size;
+       seg->skip_block_zeroing = skip_block_zeroing;
+       dm_list_init(&seg->thin_messages);
+
+       return 1;
+}
+
+int dm_tree_node_add_thin_pool_message(struct dm_tree_node *node,
+                                      dm_thin_message_t type,
+                                      uint64_t id1, uint64_t id2)
+{
+       struct thin_message *tm;
+       struct load_segment *seg;
+
+       if (!(seg = _get_single_load_segment(node, SEG_THIN_POOL)))
+               return_0;
+
+       if (!(tm = dm_pool_zalloc(node->dtree->mem, sizeof (*tm)))) {
+               log_error("Failed to allocate thin message.");
+               return 0;
+       }
+
+       switch (type) {
+       case DM_THIN_MESSAGE_CREATE_SNAP:
+               /* If the thin origin is active, it must be suspend first! */
+               if (id1 == id2) {
+                       log_error("Cannot use same device id for origin and its snapshot.");
+                       return 0;
+               }
+               if (!_thin_validate_device_id(id1) ||
+                   !_thin_validate_device_id(id2))
+                       return_0;
+               tm->message.u.m_create_snap.device_id = id1;
+               tm->message.u.m_create_snap.origin_id = id2;
+               break;
+       case DM_THIN_MESSAGE_CREATE_THIN:
+               if (!_thin_validate_device_id(id1))
+                       return_0;
+               tm->message.u.m_create_thin.device_id = id1;
+               tm->expected_errno = EEXIST;
+               break;
+       case DM_THIN_MESSAGE_DELETE:
+               if (!_thin_validate_device_id(id1))
+                       return_0;
+               tm->message.u.m_delete.device_id = id1;
+               tm->expected_errno = ENODATA;
+               break;
+       case DM_THIN_MESSAGE_SET_TRANSACTION_ID:
+               if ((id1 + 1) != id2) {
+                       log_error("New transaction id must be sequential.");
+                       return 0; /* FIXME: Maybe too strict here? */
+               }
+               if (id2 != seg->transaction_id) {
+                       log_error("Current transaction id is different from thin pool.");
+                       return 0; /* FIXME: Maybe too strict here? */
+               }
+               tm->message.u.m_set_transaction_id.current_id = id1;
+               tm->message.u.m_set_transaction_id.new_id = id2;
+               break;
+       default:
+               log_error("Unsupported message type %d.", (int) type);
+               return 0;
+       }
+
+       tm->message.type = type;
+       dm_list_add(&seg->thin_messages, &tm->list);
+
+       return 1;
+}
+
+int dm_tree_node_set_thin_pool_discard(struct dm_tree_node *node,
+                                      unsigned ignore,
+                                      unsigned no_passdown)
+{
+       struct load_segment *seg;
+
+       if (!(seg = _get_single_load_segment(node, SEG_THIN_POOL)))
+               return_0;
+
+       seg->ignore_discard = ignore;
+       seg->no_discard_passdown = no_passdown;
+
+       return 1;
+}
+
+int dm_tree_node_add_thin_target(struct dm_tree_node *node,
+                                uint64_t size,
+                                const char *pool_uuid,
+                                uint32_t device_id)
+{
+       struct dm_tree_node *pool;
+       struct load_segment *seg;
+
+       if (!(pool = dm_tree_find_node_by_uuid(node->dtree, pool_uuid))) {
+               log_error("Missing thin pool uuid %s.", pool_uuid);
+               return 0;
+       }
+
+       if (!_link_tree_nodes(node, pool))
+               return_0;
+
+       if (!_thin_validate_device_id(device_id))
+               return_0;
+
+       if (!(seg = _add_segment(node, SEG_THIN, size)))
+               return_0;
+
+       seg->pool = pool;
+       seg->device_id = device_id;
+
+       return 1;
+}
+
+int dm_tree_node_set_thin_external_origin(struct dm_tree_node *node,
+                                         const char *external_uuid)
+{
+       struct dm_tree_node *external;
+       struct load_segment *seg;
+
+       if (!(seg = _get_single_load_segment(node, SEG_THIN)))
+               return_0;
+
+       if (!(external = dm_tree_find_node_by_uuid(node->dtree,
+                                                  external_uuid))) {
+               log_error("Missing thin external origin uuid %s.",
+                         external_uuid);
+               return 0;
+       }
+
+       if (!_link_tree_nodes(node, external))
+               return_0;
+
+       seg->external = external;
+
+       return 1;
+}
+
+int dm_get_status_thin_pool(struct dm_pool *mem, const char *params,
+                           struct dm_status_thin_pool **status)
+{
+       struct dm_status_thin_pool *s;
+
+       if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_thin_pool)))) {
+               log_error("Failed to allocate thin_pool status structure.");
+               return 0;
+       }
+
+       /* FIXME: add support for held metadata root */
+       if (sscanf(params, "%" PRIu64 " %" PRIu64 "/%" PRIu64 " %" PRIu64 "/%" PRIu64,
+                  &s->transaction_id,
+                  &s->used_metadata_blocks,
+                  &s->total_metadata_blocks,
+                  &s->used_data_blocks,
+                  &s->total_data_blocks) != 5) {
+               log_error("Failed to parse thin pool params: %s.", params);
+               return 0;
+       }
+
+       *status = s;
+
+       return 1;
+}
+
+int dm_get_status_thin(struct dm_pool *mem, const char *params,
+                      struct dm_status_thin **status)
+{
+       struct dm_status_thin *s;
+
+       if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_thin)))) {
+               log_error("Failed to allocate thin status structure.");
+               return 0;
+       }
+
+       if (strchr(params, '-')) {
+               s->mapped_sectors = 0;
+               s->highest_mapped_sector = 0;
+       } else if (sscanf(params, "%" PRIu64 " %" PRIu64,
+                  &s->mapped_sectors,
+                  &s->highest_mapped_sector) != 2) {
+               log_error("Failed to parse thin params: %s.", params);
+               return 0;
+       }
+
+       *status = s;
+
+       return 1;
+}
+
 static int _add_area(struct dm_tree_node *node, struct load_segment *seg, struct dm_tree_node *dev_node, uint64_t offset)
 {
        struct seg_area *area;
@@ -2388,9 +3321,9 @@ static int _add_area(struct dm_tree_node *node, struct load_segment *seg, struct
 }
 
 int dm_tree_node_add_target_area(struct dm_tree_node *node,
-                                    const char *dev_name,
-                                    const char *uuid,
-                                    uint64_t offset)
+                                   const char *dev_name,
+                                   const char *uuid,
+                                   uint64_t offset)
 {
        struct load_segment *seg;
        struct stat info;
@@ -2409,12 +3342,12 @@ int dm_tree_node_add_target_area(struct dm_tree_node *node,
                if (!_link_tree_nodes(node, dev_node))
                        return_0;
        } else {
-               if (stat(dev_name, &info) < 0) {
+               if (stat(dev_name, &info) < 0) {
                        log_error("Device %s not found.", dev_name);
                        return 0;
                }
 
-               if (!S_ISBLK(info.st_mode)) {
+               if (!S_ISBLK(info.st_mode)) {
                        log_error("Device %s is not a block device.", dev_name);
                        return 0;
                }
@@ -2438,12 +3371,37 @@ int dm_tree_node_add_target_area(struct dm_tree_node *node,
        return 1;
 }
 
-void dm_tree_set_cookie(struct dm_tree_node *node, uint32_t cookie)
+int dm_tree_node_add_null_area(struct dm_tree_node *node, uint64_t offset)
 {
-       node->dtree->cookie = cookie;
+       struct load_segment *seg;
+
+       seg = dm_list_item(dm_list_last(&node->props.segs), struct load_segment);
+
+       switch (seg->type) {
+       case SEG_RAID1:
+       case SEG_RAID4:
+       case SEG_RAID5_LA:
+       case SEG_RAID5_RA:
+       case SEG_RAID5_LS:
+       case SEG_RAID5_RS:
+       case SEG_RAID6_ZR:
+       case SEG_RAID6_NR:
+       case SEG_RAID6_NC:
+               break;
+       default:
+               log_error("dm_tree_node_add_null_area() called on an unsupported segment type");
+               return 0;
+       }
+
+       if (!_add_area(node, seg, NULL, offset))
+               return_0;
+
+       return 1;
 }
 
-uint32_t dm_tree_get_cookie(struct dm_tree_node *node)
+void dm_tree_node_set_callback(struct dm_tree_node *dnode,
+                              dm_node_callback_fn cb, void *data)
 {
-       return node->dtree->cookie;
+       dnode->callback = cb;
+       dnode->callback_data = data;
 }
index 82fae342859ec97a1de014e53a4882667212b071..26c8241df9a342e8618fdb8e1794e542b08deb65 100644 (file)
@@ -27,6 +27,11 @@ static int _create_dir_recursive(const char *dir)
        log_verbose("Creating directory \"%s\"", dir);
        /* Create parent directories */
        orig = s = dm_strdup(dir);
+       if (!s) {
+               log_error("Failed to duplicate directory name.");
+               return 0;
+       }
+
        while ((s = strchr(s, '/')) != NULL) {
                *s = '\0';
                if (*orig) {
@@ -71,6 +76,26 @@ int dm_create_dir(const char *dir)
        return 0;
 }
 
+int dm_is_empty_dir(const char *dir)
+{
+       struct dirent *dirent;
+       DIR *d;
+
+       if (!(d = opendir(dir))) {
+               log_sys_error("opendir", dir);
+               return 0;
+       }
+
+       while ((dirent = readdir(d)))
+               if (strcmp(dirent->d_name, ".") && strcmp(dirent->d_name, ".."))
+                       break;
+
+       if (closedir(d))
+               log_sys_error("closedir", dir);
+
+       return dirent ? 0 : 1;
+}
+
 int dm_fclose(FILE *stream)
 {
        int prev_fail = ferror(stream);
@@ -110,7 +135,6 @@ retry_fcntl:
                switch (errno) {
                case EINTR:
                        goto retry_fcntl;
-                       break;
                case EACCES:
                case EAGAIN:
                        if (retries == 20) {
@@ -149,7 +173,7 @@ retry_fcntl:
                goto fail_close_unlink;
        }
 
-       if ((write_out == 0) || (write_out < bufferlen)) {
+       if ((write_out == 0) || ((size_t)write_out < bufferlen)) {
                log_error("Cannot write pid to pidfile [%s], shortwrite of"
                          "[%" PRIsize_t "] bytes, expected [%" PRIsize_t "]\n",
                          lockfile, write_out, bufferlen);
index 9b8e3c18ac9e0611d45ee4f55fbcfa79a1ed5a63..0bafa86d6cbf67f8bd9bfda29835c29c753cbda3 100644 (file)
@@ -102,7 +102,7 @@ static const struct dm_report_object_type *_find_type(struct dm_report *rh,
  */
 
 int dm_report_field_string(struct dm_report *rh,
-                          struct dm_report_field *field, const char **data)
+                          struct dm_report_field *field, const char *const *data)
 {
        char *repstr;
 
@@ -139,7 +139,7 @@ int dm_report_field_int(struct dm_report *rh,
                return 0;
        }
 
-       *sortval = (const uint64_t) value;
+       *sortval = (uint64_t) value;
        field->sort_value = sortval;
        field->report_string = repstr;
 
@@ -168,7 +168,7 @@ int dm_report_field_uint32(struct dm_report *rh,
                return 0;
        }
 
-       *sortval = (const uint64_t) value;
+       *sortval = (uint64_t) value;
        field->sort_value = sortval;
        field->report_string = repstr;
 
@@ -197,7 +197,7 @@ int dm_report_field_int32(struct dm_report *rh,
                return 0;
        }
 
-       *sortval = (const uint64_t) value;
+       *sortval = (uint64_t) value;
        field->sort_value = sortval;
        field->report_string = repstr;
 
@@ -367,33 +367,32 @@ static uint32_t _all_match(struct dm_report *rh, const char *field, size_t flen)
 {
        size_t prefix_len;
        const struct dm_report_object_type *t;
-       char prefixed_all[32];
+       uint32_t report_types = 0;
+       unsigned unprefixed_all_matched = 0;
 
        if (!strncasecmp(field, "all", 3) && flen == 3) {
-               if (strlen(rh->field_prefix)) {
-                       strcpy(prefixed_all, rh->field_prefix);
-                       strcat(prefixed_all, "all");
-                       /*
-                        * Add also prefix to receive all attributes
-                        * (e.g.LABEL/PVS use the same prefix)
-                        */
-                       return rh->report_types |
-                              _all_match(rh, prefixed_all,
-                                         strlen(prefixed_all));
-               } else
-                       return (rh->report_types)
-                               ? rh->report_types : REPORT_TYPES_ALL;
+               /* If there's no report prefix, match all report types */
+               if (!(flen = strlen(rh->field_prefix)))
+                       return rh->report_types ? : REPORT_TYPES_ALL;
+
+               /* otherwise include all fields beginning with the report prefix. */
+               unprefixed_all_matched = 1;
+               field = rh->field_prefix;
+               report_types = rh->report_types;
        }
 
+       /* Combine all report types that have a matching prefix. */
        for (t = rh->types; t->data_fn; t++) {
                prefix_len = strlen(t->prefix);
+
                if (!strncasecmp(t->prefix, field, prefix_len) &&
-                   !strncasecmp(field + prefix_len, "all", 3) &&
-                   flen == prefix_len + 3)
-                       return t->id;
+                   ((unprefixed_all_matched && (flen == prefix_len)) ||
+                    (!strncasecmp(field + prefix_len, "all", 3) &&
+                     (flen == prefix_len + 3))))
+                       report_types |= t->id;
        }
 
-       return 0;
+       return report_types;
 }
 
 /*
@@ -542,6 +541,9 @@ static int _parse_keys(struct dm_report *rh, const char *keys,
        const char *ws;         /* Word start */
        const char *we = keys;  /* Word end */
 
+       if (!keys)
+               return 1;
+
        while (*we) {
                /* Allow consecutive commas */
                while (*we && *we == ',')
@@ -675,15 +677,15 @@ int dm_report_set_output_field_name_prefix(struct dm_report *rh, const char *out
 /*
  * Create a row of data for an object
  */
-static void * _report_get_field_data(struct dm_report *rh,
-                             struct field_properties *fp, void *object)
+static void *_report_get_field_data(struct dm_report *rh,
+                                   struct field_properties *fp, void *object)
 {
-       void *ret = fp->type->data_fn(object);
+       char *ret = fp->type->data_fn(object);
 
        if (!ret)
                return NULL;
 
-       return ret + rh->fields[fp->field_num].offset;
+       return (void *)(ret + rh->fields[fp->field_num].offset);
 }
 
 int dm_report_object(struct dm_report *rh, void *object)
@@ -693,6 +695,11 @@ int dm_report_object(struct dm_report *rh, void *object)
        struct dm_report_field *field;
        void *data = NULL;
 
+       if (!rh) {
+               log_error(INTERNAL_ERROR "dm_report handler is NULL.");
+               return 0;
+       }
+
        if (!(row = dm_pool_zalloc(rh->mem, sizeof(*row)))) {
                log_error("dm_report_object: struct row allocation failed");
                return 0;
@@ -734,8 +741,8 @@ int dm_report_object(struct dm_report *rh, void *object)
                        return 0;
                }
 
-               if ((strlen(field->report_string) > field->props->width))
-                       field->props->width = strlen(field->report_string);
+               if (((int) strlen(field->report_string) > field->props->width))
+                       field->props->width = (int) strlen(field->report_string);
 
                if ((rh->flags & RH_SORT_REQUIRED) &&
                    (field->props->flags & FLD_SORT_KEY)) {
@@ -775,8 +782,8 @@ static int _report_headings(struct dm_report *rh)
        }
 
        dm_list_iterate_items(fp, &rh->field_props) {
-               if (buf_size < fp->width)
-                       buf_size = fp->width;
+               if ((int) buf_size < fp->width)
+                       buf_size = (size_t) fp->width;
        }
        /* Including trailing '\0'! */
        buf_size++;
@@ -1006,11 +1013,6 @@ static int _output_as_rows(struct dm_report *rh)
        struct dm_report_field *field;
        struct row *row;
 
-       if (!dm_pool_begin_object(rh->mem, 512)) {
-               log_error("dm_report: Unable to allocate output line");
-               return 0;
-       }
-
        dm_list_iterate_items(fp, &rh->field_props) {
                if (fp->flags & FLD_HIDDEN) {
                        dm_list_iterate_items(row, &rh->rows) {
@@ -1020,6 +1022,11 @@ static int _output_as_rows(struct dm_report *rh)
                        continue;
                }
 
+               if (!dm_pool_begin_object(rh->mem, 512)) {
+                       log_error("dm_report: Unable to allocate output line");
+                       return 0;
+               }
+
                if ((rh->flags & DM_REPORT_OUTPUT_HEADINGS)) {
                        if (!dm_pool_grow_object(rh->mem, rh->fields[fp->field_num].heading, 0)) {
                                log_error("dm_report: Failed to extend row for field name");
index 365e7ec0d33f1ad024fb8210fc7f6038220a567b..5ef633435e415db7ff2e0c762a17ae5747f4984e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2006-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of the device-mapper userspace tools.
  *
@@ -13,7 +13,6 @@
  */
 
 #include "dmlib.h"
-#include "libdevmapper.h"
 
 #include <ctype.h>
 
@@ -130,9 +129,9 @@ const char *dm_basename(const char *path)
        return p ? p + 1 : path;
 }
 
-int dm_asprintf(char **result, const char *format, ...)
+int dm_vasprintf(char **result, const char *format, va_list aq)
 {
-       int n, ok = 0, size = 32;
+       int i, n, size = 16;
        va_list ap;
        char *buf = dm_malloc(size);
 
@@ -141,23 +140,293 @@ int dm_asprintf(char **result, const char *format, ...)
        if (!buf)
                return -1;
 
-       while (!ok) {
-               va_start(ap, format);
+       for (i = 0;; i++) {
+               va_copy(ap, aq);
                n = vsnprintf(buf, size, format, ap);
                va_end(ap);
 
                if (0 <= n && n < size)
-                       ok = 1;
-               else {
+                       break;
+
+               dm_free(buf);
+               /* Up to glibc 2.0.6 returns -1 */
+               size = (n < 0) ? size * 2 : n + 1;
+               if (!(buf = dm_malloc(size)))
+                       return -1;
+       }
+
+       if (i > 1) {
+               /* Reallocating more then once? */
+               if (!(*result = dm_strdup(buf))) {
                        dm_free(buf);
-                       size *= 2;
-                       buf = dm_malloc(size);
-                       if (!buf)
-                               return -1;
+                       return -1;
                }
-       }
+               dm_free(buf);
+       } else
+               *result = buf;
 
-       *result = dm_strdup(buf);
-       dm_free(buf);
        return n + 1;
 }
+
+int dm_asprintf(char **result, const char *format, ...)
+{
+       int r;
+       va_list ap;
+       va_start(ap, format);
+       r = dm_vasprintf(result, format, ap);
+       va_end(ap);
+       return r;
+}
+
+/*
+ * Count occurences of 'c' in 'str' until we reach a null char.
+ *
+ * Returns:
+ *  len - incremented for each char we encounter.
+ *  count - number of occurrences of 'c' and 'c2'.
+ */
+static void _count_chars(const char *str, size_t *len, int *count,
+                        const int c1, const int c2)
+{
+       const char *ptr;
+
+       for (ptr = str; *ptr; ptr++, (*len)++)
+               if (*ptr == c1 || *ptr == c2)
+                       (*count)++;
+}
+
+/*
+ * Count occurrences of 'c' in 'str' of length 'size'.
+ *
+ * Returns:
+ *   Number of occurrences of 'c'
+ */
+unsigned dm_count_chars(const char *str, size_t len, const int c)
+{
+       size_t i;
+       unsigned count = 0;
+
+       for (i = 0; i < len; i++)
+               if (str[i] == c)
+                       count++;
+
+       return count;
+}
+
+/*
+ * Length of string after escaping double quotes and backslashes.
+ */
+size_t dm_escaped_len(const char *str)
+{
+       size_t len = 1;
+       int count = 0;
+
+       _count_chars(str, &len, &count, '\"', '\\');
+
+       return count + len;
+}
+
+/*
+ * Copies a string, quoting orig_char with quote_char.
+ * Optionally also quote quote_char.
+ */
+static void _quote_characters(char **out, const char *src,
+                             const int orig_char, const int quote_char,
+                             int quote_quote_char)
+{
+       while (*src) {
+               if (*src == orig_char ||
+                   (*src == quote_char && quote_quote_char))
+                       *(*out)++ = quote_char;
+
+               *(*out)++ = *src++;
+       }
+}
+
+static void _unquote_one_character(char *src, const char orig_char,
+                                  const char quote_char)
+{
+       char *out;
+       char s, n;
+
+       /* Optimise for the common case where no changes are needed. */
+       while ((s = *src++)) {
+               if (s == quote_char &&
+                   ((n = *src) == orig_char || n == quote_char)) {
+                       out = src++;
+                       *(out - 1) = n;
+
+                       while ((s = *src++)) {
+                               if (s == quote_char &&
+                                   ((n = *src) == orig_char || n == quote_char)) {
+                                       s = n;
+                                       src++;
+                               }
+                               *out = s;
+                               out++;
+                       }
+
+                       *out = '\0';
+                       return;
+               }
+       }
+}
+
+/*
+ * Unquote each character given in orig_char array and unquote quote_char
+ * as well. Also save the first occurrence of each character from orig_char
+ * that was found unquoted in arr_substr_first_unquoted array. This way we can
+ * process several characters in one go.
+ */
+static void _unquote_characters(char *src, const char *orig_chars,
+                               size_t num_orig_chars,
+                               const char quote_char,
+                               char *arr_substr_first_unquoted[])
+{
+       char *out = src;
+       char c, s, n;
+       unsigned i;
+
+       while ((s = *src++)) {
+               for (i = 0; i < num_orig_chars; i++) {
+                       c = orig_chars[i];
+                       if (s == quote_char &&
+                           ((n = *src) == c || n == quote_char)) {
+                               s = n;
+                               src++;
+                               break;
+                       }
+                       if (arr_substr_first_unquoted && (s == c) &&
+                           !arr_substr_first_unquoted[i])
+                               arr_substr_first_unquoted[i] = out;
+               };
+               *out++ = s;
+       }
+
+       *out = '\0';
+}
+
+/*
+ * Copies a string, quoting hyphens with hyphens.
+ */
+static void _quote_hyphens(char **out, const char *src)
+{
+       _quote_characters(out, src, '-', '-', 0);
+}
+
+/*
+ * <vg>-<lv>-<layer> or if !layer just <vg>-<lv>.
+ */
+char *dm_build_dm_name(struct dm_pool *mem, const char *vgname,
+                      const char *lvname, const char *layer)
+{
+       size_t len = 1;
+       int hyphens = 1;
+       char *r, *out;
+
+       _count_chars(vgname, &len, &hyphens, '-', 0);
+       _count_chars(lvname, &len, &hyphens, '-', 0);
+
+       if (layer && *layer) {
+               _count_chars(layer, &len, &hyphens, '-', 0);
+               hyphens++;
+       }
+
+       len += hyphens;
+
+       if (!(r = dm_pool_alloc(mem, len))) {
+               log_error("build_dm_name: Allocation failed for %" PRIsize_t
+                         " for %s %s %s.", len, vgname, lvname, layer);
+               return NULL;
+       }
+
+       out = r;
+       _quote_hyphens(&out, vgname);
+       *out++ = '-';
+       _quote_hyphens(&out, lvname);
+
+       if (layer && *layer) {
+               /* No hyphen if the layer begins with _ e.g. _mlog */
+               if (*layer != '_')
+                       *out++ = '-';
+               _quote_hyphens(&out, layer);
+       }
+       *out = '\0';
+
+       return r;
+}
+
+char *dm_build_dm_uuid(struct dm_pool *mem, const char *uuid_prefix, const char *lvid, const char *layer)
+{
+       char *dmuuid;
+       size_t len;
+
+       if (!layer)
+               layer = "";
+
+       len = strlen(uuid_prefix) + strlen(lvid) + strlen(layer) + 2;
+
+       if (!(dmuuid = dm_pool_alloc(mem, len))) {
+               log_error("build_dm_name: Allocation failed for %" PRIsize_t
+                         " %s %s.", len, lvid, layer);
+               return NULL;
+       }
+
+       sprintf(dmuuid, "%s%s%s%s", uuid_prefix, lvid, (*layer) ? "-" : "", layer);
+
+       return dmuuid;
+}
+
+/*
+ * Copies a string, quoting double quotes with backslashes.
+ */
+char *dm_escape_double_quotes(char *out, const char *src)
+{
+       char *buf = out;
+
+       _quote_characters(&buf, src, '\"', '\\', 1);
+       *buf = '\0';
+
+       return out;
+}
+
+/*
+ * Undo quoting in situ.
+ */
+void dm_unescape_double_quotes(char *src)
+{
+       _unquote_one_character(src, '\"', '\\');
+}
+
+/*
+ * Unescape colons and "at" signs in situ and save the substrings
+ * starting at the position of the first unescaped colon and the
+ * first unescaped "at" sign. This is normally used to unescape
+ * device names used as PVs.
+ */
+void dm_unescape_colons_and_at_signs(char *src,
+                                    char **substr_first_unquoted_colon,
+                                    char **substr_first_unquoted_at_sign)
+{
+       const char *orig_chars = ":@";
+       char *arr_substr_first_unquoted[] = {NULL, NULL, NULL};
+
+       _unquote_characters(src, orig_chars, 2, '\\', arr_substr_first_unquoted);
+
+       if (substr_first_unquoted_colon)
+               *substr_first_unquoted_colon = arr_substr_first_unquoted[0];
+
+       if (substr_first_unquoted_at_sign)
+               *substr_first_unquoted_at_sign = arr_substr_first_unquoted[1];
+}
+
+int dm_strncpy(char *dest, const char *src, size_t n)
+{
+       if (memccpy(dest, src, 0, n))
+               return 1;
+
+       if (n > 0)
+               dest[n - 1] = '\0';
+
+       return 0;
+}
index fb11b5c7b54a5564b68ad09b8d96482b54e0701d..1cf66fef419670b6eab390e0f8d2d611d9fa0c70 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001 - 2003 Sistina Software (UK) Limited.
- * Copyright (C) 2004 - 2009 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004 - 2012 Red Hat, Inc. All rights reserved.
  *
  * This file is released under the LGPL.
  */
@@ -269,9 +269,9 @@ enum {
 #define DM_DEV_SET_GEOMETRY    _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
 
 #define DM_VERSION_MAJOR       4
-#define DM_VERSION_MINOR       19
+#define DM_VERSION_MINOR       23
 #define DM_VERSION_PATCHLEVEL  0
-#define DM_VERSION_EXTRA       "-ioctl (2010-10-14)"
+#define DM_VERSION_EXTRA       "-ioctl (2012-07-25)"
 
 /* Status bits */
 #define DM_READONLY_FLAG       (1 << 0) /* In/Out */
@@ -309,6 +309,8 @@ enum {
 
 /*
  * Set this to suspend without flushing queued ios.
+ * Also disables flushing uncommitted changes in the thin target before
+ * generating statistics for DM_TABLE_STATUS and DM_DEV_WAIT.
  */
 #define DM_NOFLUSH_FLAG                (1 << 11) /* In */
 
@@ -330,4 +332,10 @@ enum {
  */
 #define DM_UUID_FLAG                   (1 << 14) /* In */
 
+/*
+ * If set, all buffers are wiped after use. Use when sending
+ * or requesting sensitive data such as an encryption key.
+ */
+#define DM_SECURE_DATA_FLAG            (1 << 15) /* In */
+
 #endif                         /* _LINUX_DM_IOCTL_H */
index 7cacb18456a77ca05b5153ad4eaba9cf76f3c8ad..331793867c2c3bbb92fab1ef0753b7a068be2806 100644 (file)
  * Payload-to-userspace:
  *     A single string containing all the argv arguments separated by ' 's
  * Payload-to-kernel:
- *     None.  ('data_size' in the dm_ulog_request struct should be 0.)
+ *     The name of the device that is used as the backing store for the log
+ *      data.  'dm_get_device' will be called on this device.  ('dm_put_device'
+ *      will be called on this device automatically after calling DM_ULOG_DTR.)
+ *      If there is no device needed for log data, 'data_size' in the
+ *      dm_ulog_request struct should be 0.
  *
  * The UUID contained in the dm_ulog_request structure is the reference that
  * will be used by all request types to a specific log.  The constructor must
- * record this assotiation with instance created.
+ * record this assotiation with the instance created.
  *
  * When the request has been processed, user-space must return the
- * dm_ulog_request to the kernel - setting the 'error' field and
- * 'data_size' appropriately.
+ * dm_ulog_request to the kernel - setting the 'error' field, filling the
+ * data field with the log device if necessary, and setting 'data_size'
+ * appropriately.
  */
 #define DM_ULOG_CTR                    1
 
  * various request types above.  The remaining 24-bits are currently
  * set to zero and are reserved for future use and compatibility concerns.
  *
- * User-space should always use DM_ULOG_REQUEST_TYPE to aquire the
+ * User-space should always use DM_ULOG_REQUEST_TYPE to acquire the
  * request type from the 'request_type' field to maintain forward compatibility.
  */
 #define DM_ULOG_REQUEST_MASK 0xFF
 #define DM_ULOG_REQUEST_TYPE(request_type) \
        (DM_ULOG_REQUEST_MASK & (request_type))
 
+/*
+ * DM_ULOG_REQUEST_VERSION is incremented when there is a
+ * change to the way information is passed between kernel
+ * and userspace.  This could be a structure change of
+ * dm_ulog_request or a change in the way requests are
+ * issued/handled.  Changes are outlined here:
+ *     version 1:  Initial implementation
+ *     version 2:  DM_ULOG_CTR allowed to return a string containing a
+ *                 device name that is to be registered with DM via
+ *                 'dm_get_device'.
+ */
+#define DM_ULOG_REQUEST_VERSION 2
+
 struct dm_ulog_request {
        /*
         * The local unique identifier (luid) and the universally unique
@@ -383,8 +401,9 @@ struct dm_ulog_request {
         */
        uint64_t luid;
        char uuid[DM_UUID_LEN];
-       char padding[7];        /* Padding because DM_UUID_LEN = 129 */
+       char padding[3];        /* Padding because DM_UUID_LEN = 129 */
 
+       uint32_t version;       /* See DM_ULOG_REQUEST_VERSION */
        int32_t error;          /* Used to report back processing errors */
 
        uint32_t seq;           /* Sequence number for request */
index db7f5f3ed77b21ffbfa34deffc9f38521edce036..d37083fcd90347be2ac36103cd83e965ce5340de 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.  
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of the device-mapper userspace tools.
  *
 
 #include "dmlib.h"
 
+#ifdef VALGRIND_POOL
+#include "memcheck.h"
+#endif
+
 #include <assert.h>
 #include <stdarg.h>
 
@@ -115,7 +119,9 @@ void *dm_malloc_aux_debug(size_t s, const char *file, int line)
 
        /* log_debug("Allocated: %u %u %u", nb->id, _mem_stats.blocks_allocated,
                  _mem_stats.bytes); */
-
+#ifdef VALGRIND_POOL
+       VALGRIND_MAKE_MEM_UNDEFINED(nb + 1, s);
+#endif
        return nb + 1;
 }
 
@@ -141,11 +147,13 @@ void dm_free_aux(void *p)
 
        /* sanity check */
        assert(mb->magic == p);
-
+#ifdef VALGRIND_POOL
+       VALGRIND_MAKE_MEM_DEFINED(p, mb->length);
+#endif
        /* check data at the far boundary */
-       ptr = ((char *) mb) + sizeof(struct memblock) + mb->length;
+       ptr = (char *) p + mb->length;
        for (i = 0; i < sizeof(unsigned long); i++)
-               if (*ptr++ != (char) mb->id)
+               if (ptr[i] != (char) mb->id)
                        assert(!"Damage at far end of block");
 
        /* have we freed this before ? */
@@ -165,9 +173,9 @@ void dm_free_aux(void *p)
        mb->id = 0;
 
        /* stomp a different pattern across the memory */
-       ptr = ((char *) mb) + sizeof(struct memblock);
+       ptr = p;
        for (i = 0; i < mb->length; i++)
-               *ptr++ = i & 1 ? (char) 0xde : (char) 0xad;
+               ptr[i] = i & 1 ? (char) 0xde : (char) 0xad;
 
        assert(_mem_stats.blocks_allocated);
        _mem_stats.blocks_allocated--;
@@ -184,7 +192,7 @@ void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line)
 
        r = dm_malloc_aux_debug(s, file, line);
 
-       if (p) {
+       if (r && p) {
                memcpy(r, p, mb->length);
                dm_free_aux(p);
        }
diff --git a/libdm/mm/dbg_malloc.h b/libdm/mm/dbg_malloc.h
deleted file mode 100644 (file)
index 6de1020..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.  
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
- *
- * This file is part of the device-mapper userspace tools.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU Lesser General Public License v.2.1.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#ifndef _DM_DBG_MALLOC_H
-#define _DM_DBG_MALLOC_H
-
-#include <stdlib.h>
-#include <string.h>
-
-void *malloc_aux(size_t s, const char *file, int line);
-#define dm_malloc(s) malloc_aux((s), __FILE__, __LINE__)
-
-char *dbg_strdup(const char *str);
-
-#ifdef DEBUG_MEM
-
-void free_aux(void *p);
-void *realloc_aux(void *p, unsigned int s, const char *file, int line);
-int dump_memory(void);
-void bounds_check(void);
-
-#  define dm_free(p) free_aux(p)
-#  define dbg_realloc(p, s) realloc_aux(p, s, __FILE__, __LINE__)
-
-#else
-
-#  define dm_free(p) do {if (p) free(p); } while (0)
-#  define dbg_realloc(p, s) realloc(p, s)
-#  define dump_memory()
-#  define bounds_check()
-
-#endif
-
-#endif
index 7fde3a6f76273da0d3f1884b16c8f19ce32cde36..7f9a0e4071dbc213582297a9ec7620f9da93d6ff 100644 (file)
@@ -33,6 +33,8 @@ struct dm_pool {
        struct dm_list list;
        const char *name;
        void *orig_pool;        /* to pair it with first allocation call */
+       unsigned locked;
+       long crc;
 
        int begun;
        struct block *object;
@@ -48,7 +50,7 @@ struct dm_pool {
 
 struct dm_pool *dm_pool_create(const char *name, size_t chunk_hint)
 {
-       struct dm_pool *mem = dm_malloc(sizeof(*mem));
+       struct dm_pool *mem = dm_zalloc(sizeof(*mem));
 
        if (!mem) {
                log_error("Couldn't create memory pool %s (size %"
@@ -57,16 +59,6 @@ struct dm_pool *dm_pool_create(const char *name, size_t chunk_hint)
        }
 
        mem->name = name;
-       mem->begun = 0;
-       mem->object = 0;
-       mem->blocks = mem->tail = NULL;
-
-       mem->stats.block_serialno = 0;
-       mem->stats.blocks_allocated = 0;
-       mem->stats.blocks_max = 0;
-       mem->stats.bytes = 0;
-       mem->stats.maxbytes = 0;
-
        mem->orig_pool = mem;
 
 #ifdef DEBUG_POOL
@@ -81,6 +73,10 @@ static void _free_blocks(struct dm_pool *p, struct block *b)
 {
        struct block *n;
 
+       if (p->locked)
+               log_error(INTERNAL_ERROR "_free_blocks from locked pool %s",
+                         p->name);
+
        while (b) {
                p->stats.bytes -= b->size;
                p->stats.blocks_allocated--;
@@ -119,6 +115,10 @@ void *dm_pool_alloc(struct dm_pool *p, size_t s)
 
 static void _append_block(struct dm_pool *p, struct block *b)
 {
+       if (p->locked)
+               log_error(INTERNAL_ERROR "_append_blocks to locked pool %s",
+                         p->name);
+
        if (p->tail) {
                p->tail->next = b;
                p->tail = b;
@@ -146,7 +146,7 @@ static struct block *_new_block(size_t s, unsigned alignment)
         * I don't think LVM will use anything but default
         * align.
         */
-       assert(alignment == DEFAULT_ALIGNMENT);
+       assert(alignment <= DEFAULT_ALIGNMENT);
 
        if (!b) {
                log_error("Out of memory");
@@ -226,6 +226,10 @@ int dm_pool_grow_object(struct dm_pool *p, const void *extra, size_t delta)
        struct block *new;
        size_t new_size;
 
+       if (p->locked)
+               log_error(INTERNAL_ERROR "Grow objects in locked pool %s",
+                         p->name);
+
        if (!delta)
                delta = strlen(extra);
 
@@ -248,7 +252,7 @@ int dm_pool_grow_object(struct dm_pool *p, const void *extra, size_t delta)
        }
        p->object = new;
 
-       memcpy(new->data + new_size - delta, extra, delta);
+       memcpy((char*)new->data + new_size - delta, extra, delta);
 
        return 1;
 }
@@ -270,3 +274,19 @@ void dm_pool_abandon_object(struct dm_pool *p)
        p->begun = 0;
        p->object = NULL;
 }
+
+static long _pool_crc(const struct dm_pool *p)
+{
+#ifndef DEBUG_ENFORCE_POOL_LOCKING
+#warning pool crc not implemented with pool debug
+#endif
+       return 0;
+}
+
+static int _pool_protect(struct dm_pool *p, int prot)
+{
+#ifdef DEBUG_ENFORCE_POOL_LOCKING
+#warning pool mprotect not implemented with pool debug
+#endif
+       return 1;
+}
index ebd982e6d7ede256e713ae40b954c0192e05eb2c..61e076a1e2d2fc8c04ac15d7fa4157667ffaca99 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of the device-mapper userspace tools.
  *
  */
 
 #ifdef VALGRIND_POOL
-#include "valgrind/memcheck.h"
+#include "memcheck.h"
 #endif
 
 #include "dmlib.h"
+#include <malloc.h>
 
 struct chunk {
        char *begin, *end;
        struct chunk *prev;
-};
+} __attribute__((aligned(8)));
 
 struct dm_pool {
        struct dm_list list;
        struct chunk *chunk, *spare_chunk;      /* spare_chunk is a one entry free
                                                   list to stop 'bobbling' */
+       const char *name;
        size_t chunk_size;
        size_t object_len;
        unsigned object_alignment;
+       int locked;
+       long crc;
 };
 
 static void _align_chunk(struct chunk *c, unsigned alignment);
@@ -51,6 +55,7 @@ struct dm_pool *dm_pool_create(const char *name, size_t chunk_hint)
                return 0;
        }
 
+       p->name = name;
        /* round chunk_hint up to the next power of 2 */
        p->chunk_size = chunk_hint + sizeof(struct chunk);
        while (new_size < p->chunk_size)
@@ -236,6 +241,9 @@ void *dm_pool_end_object(struct dm_pool *p)
 
 void dm_pool_abandon_object(struct dm_pool *p)
 {
+#ifdef VALGRIND_POOL
+       VALGRIND_MAKE_MEM_NOACCESS(p->chunk, p->object_len);
+#endif
        p->object_len = 0;
        p->object_alignment = DEFAULT_ALIGNMENT;
 }
@@ -250,12 +258,28 @@ static struct chunk *_new_chunk(struct dm_pool *p, size_t s)
        struct chunk *c;
 
        if (p->spare_chunk &&
-           ((p->spare_chunk->end - p->spare_chunk->begin) >= s)) {
+           ((p->spare_chunk->end - p->spare_chunk->begin) >= (ptrdiff_t)s)) {
                /* reuse old chunk */
                c = p->spare_chunk;
                p->spare_chunk = 0;
        } else {
-               if (!(c = dm_malloc(s))) {
+#ifdef DEBUG_ENFORCE_POOL_LOCKING
+               if (!pagesize) {
+                       pagesize = getpagesize(); /* lvm_pagesize(); */
+                       pagesize_mask = pagesize - 1;
+               }
+               /*
+                * Allocate page aligned size so malloc could work.
+                * Otherwise page fault would happen from pool unrelated
+                * memory writes of internal malloc pointers.
+                */
+#  define aligned_malloc(s)    (posix_memalign((void**)&c, pagesize, \
+                                               ALIGN_ON_PAGE(s)) == 0)
+#else
+#  define aligned_malloc(s)    (c = dm_malloc(s))
+#endif /* DEBUG_ENFORCE_POOL_LOCKING */
+               if (!aligned_malloc(s)) {
+#undef aligned_malloc
                        log_error("Out of memory.  Requested %" PRIsize_t
                                  " bytes.", s);
                        return NULL;
@@ -276,11 +300,59 @@ static struct chunk *_new_chunk(struct dm_pool *p, size_t s)
 
 static void _free_chunk(struct chunk *c)
 {
-       if (c) {
 #ifdef VALGRIND_POOL
-               VALGRIND_MAKE_MEM_UNDEFINED(c, c->end - (char *) c);
+#  ifdef DEBUG_MEM
+       if (c)
+               VALGRIND_MAKE_MEM_UNDEFINED(c + 1, c->end - (char *) (c + 1));
+#  endif
+#endif
+#ifdef DEBUG_ENFORCE_POOL_LOCKING
+       /* since DEBUG_MEM is using own memory list */
+       free(c); /* for posix_memalign() */
+#else
+       dm_free(c);
+#endif
+}
+
+
+/**
+ * Calc crc/hash from pool's memory chunks with internal pointers
+ */
+static long _pool_crc(const struct dm_pool *p)
+{
+       long crc_hash = 0;
+#ifndef DEBUG_ENFORCE_POOL_LOCKING
+       const struct chunk *c;
+       const long *ptr, *end;
+
+       for (c = p->chunk; c; c = c->prev) {
+               end = (const long *) (c->begin < c->end ? (long) c->begin & ~7: (long) c->end);
+               ptr = (const long *) c;
+#ifdef VALGRIND_POOL
+               VALGRIND_MAKE_MEM_DEFINED(ptr, (end - ptr) * sizeof(*end));
 #endif
+               while (ptr < end) {
+                       crc_hash += *ptr++;
+                       crc_hash += (crc_hash << 10);
+                       crc_hash ^= (crc_hash >> 6);
+               }
+       }
+#endif /* DEBUG_ENFORCE_POOL_LOCKING */
+
+       return crc_hash;
+}
+
+static int _pool_protect(struct dm_pool *p, int prot)
+{
+#ifdef DEBUG_ENFORCE_POOL_LOCKING
+       struct chunk *c;
 
-               dm_free(c);
+       for (c = p->chunk; c; c = c->prev) {
+               if (mprotect(c, (size_t) ((c->end - (char *) c) - 1), prot) != 0) {
+                       log_sys_error("mprotect", "");
+                       return 0;
+               }
        }
+#endif
+       return 1;
 }
index 35bfffae426ed39bed7f0e37d6dd6ae0b0c4285b..b81a9b6651cc4edc3e306f9aec431b3ce620a6ab 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.  
- * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of the device-mapper userspace tools.
  *
  */
 
 #include "dmlib.h"
+#include <sys/mman.h>
 
 /* FIXME: thread unsafe */
 static DM_LIST_INIT(_dm_pools);
 void dm_pools_check_leaks(void);
 
+#ifdef DEBUG_ENFORCE_POOL_LOCKING
+#ifdef DEBUG_POOL
+#error Do not use DEBUG_POOL with DEBUG_ENFORCE_POOL_LOCKING
+#endif
+
+/*
+ * Use mprotect system call to ensure all locked pages are not writable.
+ * Generates segmentation fault with write access to the locked pool.
+ *
+ * - Implementation is using posix_memalign() to get page aligned
+ *   memory blocks (could be implemented also through malloc).
+ * - Only pool-fast is properly handled for now.
+ * - Checksum is slower compared to mprotect.
+ */
+static size_t pagesize = 0;
+static size_t pagesize_mask = 0;
+#define ALIGN_ON_PAGE(size) (((size) + (pagesize_mask)) & ~(pagesize_mask))
+#endif
+
 #ifdef DEBUG_POOL
 #include "pool-debug.c"
 #else
@@ -27,7 +47,7 @@ void dm_pools_check_leaks(void);
 
 char *dm_pool_strdup(struct dm_pool *p, const char *str)
 {
-       char *ret = dm_pool_alloc(p, strlen(str) + 1);
+       char *ret = dm_pool_alloc_aligned(p, strlen(str) + 1, 2);
 
        if (ret)
                strcpy(ret, str);
@@ -37,7 +57,7 @@ char *dm_pool_strdup(struct dm_pool *p, const char *str)
 
 char *dm_pool_strndup(struct dm_pool *p, const char *str, size_t n)
 {
-       char *ret = dm_pool_alloc(p, n + 1);
+       char *ret = dm_pool_alloc_aligned(p, n + 1, 2);
 
        if (ret) {
                strncpy(ret, str, n);
@@ -71,7 +91,93 @@ void dm_pools_check_leaks(void)
                          p->orig_pool,
                          p->name, p->stats.bytes);
 #else
-               log_error(" [%p]", p);
+               log_error(" [%p] %s", p, p->name);
 #endif
        }
+       log_error(INTERNAL_ERROR "Unreleased memory pool(s) found.");
+}
+
+/**
+ * Status of locked pool.
+ *
+ * \param p
+ * Pool to be tested for lock status.
+ *
+ * \return
+ * 1 when the pool is locked, 0 otherwise.
+ */
+int dm_pool_locked(struct dm_pool *p)
+{
+       return p->locked;
+}
+
+/**
+ * Lock memory pool.
+ *
+ * \param p
+ * Pool to be locked.
+ *
+ * \param crc
+ * Bool specifies whether to store the pool crc/hash checksum.
+ *
+ * \return
+ * 1 (success) when the pool was preperly locked, 0 otherwise.
+ */
+int dm_pool_lock(struct dm_pool *p, int crc)
+{
+       if (p->locked) {
+               log_error(INTERNAL_ERROR "Pool %s is already locked.",
+                         p->name);
+               return 0;
+       }
+
+       if (crc)
+               p->crc = _pool_crc(p);  /* Get crc for pool */
+
+       if (!_pool_protect(p, PROT_READ)) {
+               _pool_protect(p, PROT_READ | PROT_WRITE);
+               return_0;
+       }
+
+       p->locked = 1;
+
+       log_debug("Pool %s is locked.", p->name);
+
+       return 1;
+}
+
+/**
+ * Unlock memory pool.
+ *
+ * \param p
+ * Pool to be unlocked.
+ *
+ * \param crc
+ * Bool enables compare of the pool crc/hash with the stored value
+ * at pool lock. The pool is not properly unlocked if there is a mismatch.
+ *
+ * \return
+ * 1 (success) when the pool was properly unlocked, 0 otherwise.
+ */
+int dm_pool_unlock(struct dm_pool *p, int crc)
+{
+       if (!p->locked) {
+               log_error(INTERNAL_ERROR "Pool %s is already unlocked.",
+                         p->name);
+               return 0;
+       }
+
+       p->locked = 0;
+
+       if (!_pool_protect(p, PROT_READ | PROT_WRITE))
+               return_0;
+
+       log_debug("Pool %s is unlocked.", p->name);
+
+       if (crc && (p->crc != _pool_crc(p))) {
+               log_error(INTERNAL_ERROR "Pool %s crc mismatch.", p->name);
+               return 0;
+       }
+
+       return 1;
 }
index 9590865861ff2c0dfecd9cd7fe9f484136946e3d..aa58d985d1fdd5580a0ebbca460bdcfa07d17be0 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of the device-mapper userspace tools.
  *
@@ -98,21 +98,27 @@ static void _fill_table(struct dm_regex *m, struct rx_node *rx)
                 m->charsets[m->charsets_entered++] = rx;
 }
 
-static void _create_bitsets(struct dm_regex *m)
+static int _create_bitsets(struct dm_regex *m)
 {
-       int i;
+       unsigned i;
+       struct rx_node *n;
 
        for (i = 0; i < m->num_nodes; i++) {
-               struct rx_node *n = m->nodes[i];
-               n->firstpos = dm_bitset_create(m->scratch, m->num_charsets);
-               n->lastpos = dm_bitset_create(m->scratch, m->num_charsets);
-               n->followpos = dm_bitset_create(m->scratch, m->num_charsets);
+               n = m->nodes[i];
+               if (!(n->firstpos = dm_bitset_create(m->scratch, m->num_charsets)))
+                       return_0;
+               if (!(n->lastpos = dm_bitset_create(m->scratch, m->num_charsets)))
+                       return_0;
+               if (!(n->followpos = dm_bitset_create(m->scratch, m->num_charsets)))
+                       return_0;
        }
+
+       return 1;
 }
 
 static void _calc_functions(struct dm_regex *m)
 {
-       int i, j, final = 1;
+       unsigned i, j, final = 1;
        struct rx_node *rx, *c1, *c2;
 
        for (i = 0; i < m->num_nodes; i++) {
@@ -206,14 +212,17 @@ static struct dfa_state *_create_state_queue(struct dm_pool *mem,
                                              struct dfa_state *dfa,
                                              dm_bitset_t bits)
 {
-       dfa->bits = dm_bitset_create(mem, bits[0]);     /* first element is the size */
+       if (!(dfa->bits = dm_bitset_create(mem, bits[0])))  /* first element is the size */
+               return_NULL;
+
        dm_bit_copy(dfa->bits, bits);
        dfa->next = 0;
-        dfa->final = -1;
+       dfa->final = -1;
+
        return dfa;
 }
 
-static void _calc_state(struct dm_regex *m, struct dfa_state *dfa, int a)
+static int _calc_state(struct dm_regex *m, struct dfa_state *dfa, int a)
 {
         int set_bits = 0, i;
         dm_bitset_t dfa_bits = dfa->bits;
@@ -233,9 +242,12 @@ static void _calc_state(struct dm_regex *m, struct dfa_state *dfa, int a)
                 struct dfa_state *ldfa = ttree_lookup(m->tt, m->bs + 1);
                 if (!ldfa) {
                         /* push */
-                        ldfa = _create_dfa_state(m->mem);
-                        ttree_insert(m->tt, m->bs + 1, ldfa);
-                        tmp = _create_state_queue(m->scratch, ldfa, m->bs);
+                       if (!(ldfa = _create_dfa_state(m->mem)))
+                               return_0;
+
+                       ttree_insert(m->tt, m->bs + 1, ldfa);
+                       if (!(tmp = _create_state_queue(m->scratch, ldfa, m->bs)))
+                               return_0;
                         if (!m->h)
                                 m->h = m->t = tmp;
                         else {
@@ -247,31 +259,32 @@ static void _calc_state(struct dm_regex *m, struct dfa_state *dfa, int a)
                 dfa->lookup[a] = ldfa;
                 dm_bit_clear_all(m->bs);
         }
+
+       return 1;
 }
 
 static int _calc_states(struct dm_regex *m, struct rx_node *rx)
 {
        unsigned iwidth = (m->num_charsets / DM_BITS_PER_INT) + 1;
        struct dfa_state *dfa;
-       int i, a;
+       struct rx_node *n;
+       unsigned i;
+       int a;
 
-       m->tt = ttree_create(m->scratch, iwidth);
-       if (!m->tt)
+       if (!(m->tt = ttree_create(m->scratch, iwidth)))
                return_0;
 
        if (!(m->bs = dm_bitset_create(m->scratch, m->num_charsets)))
                return_0;
 
         /* build some char maps */
-        for (a = 0; a < 256; a++) {
-                m->charmap[a] = dm_bitset_create(m->scratch, m->num_charsets);
-                if (!m->charmap[a])
-                        return_0;
-        }
+        for (a = 0; a < 256; a++)
+               if (!(m->charmap[a] = dm_bitset_create(m->scratch, m->num_charsets)))
+                       return_0;
 
         for (i = 0; i < m->num_nodes; i++) {
-                struct rx_node *n = m->nodes[i];
-                if (n->type == CHARSET) {
+               n = m->nodes[i];
+                        if (n->type == CHARSET) {
                         for (a = dm_bit_get_first(n->charset);
                              a >= 0; a = dm_bit_get_next(n->charset, a))
                                 dm_bit_set(m->charmap[a], n->charset_index);
@@ -279,13 +292,19 @@ static int _calc_states(struct dm_regex *m, struct rx_node *rx)
         }
 
        /* create first state */
-       dfa = _create_dfa_state(m->mem);
+       if (!(dfa = _create_dfa_state(m->mem)))
+               return_0;
+
        m->start = dfa;
        ttree_insert(m->tt, rx->firstpos + 1, dfa);
 
        /* prime the queue */
-       m->h = m->t = _create_state_queue(m->scratch, dfa, rx->firstpos);
-        m->dfa_copy = dm_bitset_create(m->scratch, m->num_charsets);
+       if (!(m->h = m->t = _create_state_queue(m->scratch, dfa, rx->firstpos)))
+               return_0;
+
+       if (!(m->dfa_copy = dm_bitset_create(m->scratch, m->num_charsets)))
+               return_0;
+
        return 1;
 }
 
@@ -293,7 +312,7 @@ static int _calc_states(struct dm_regex *m, struct rx_node *rx)
  * Forces all the dfa states to be calculated up front, ie. what
  * _calc_states() used to do before we switched to calculating on demand.
  */
-static void _force_states(struct dm_regex *m)
+static int _force_states(struct dm_regex *m)
 {
         int a;
 
@@ -306,15 +325,18 @@ static void _force_states(struct dm_regex *m)
                 /* iterate through all the inputs for this state */
                 dm_bit_clear_all(m->bs);
                 for (a = 0; a < 256; a++)
-                        _calc_state(m, s, a);
+                       if (!_calc_state(m, s, a))
+                               return_0;
         }
+
+        return 1;
 }
 
 struct dm_regex *dm_regex_create(struct dm_pool *mem, const char * const *patterns,
                                 unsigned num_patterns)
 {
        char *all, *ptr;
-       int i;
+       unsigned i;
        size_t len = 0;
        struct rx_node *rx;
        struct dm_regex *m;
@@ -347,24 +369,29 @@ struct dm_regex *dm_regex_create(struct dm_pool *mem, const char * const *patter
        m->mem = mem;
        m->scratch = scratch;
        m->num_nodes = _count_nodes(rx);
-        m->num_charsets = _count_charsets(rx);
-        _enumerate_charsets(rx);
-       m->nodes = dm_pool_alloc(scratch, sizeof(*m->nodes) * m->num_nodes);
-       if (!m->nodes)
+       m->num_charsets = _count_charsets(rx);
+       _enumerate_charsets(rx);
+       if (!(m->nodes = dm_pool_alloc(scratch, sizeof(*m->nodes) * m->num_nodes)))
                goto_bad;
 
-        m->charsets = dm_pool_alloc(scratch, sizeof(*m->charsets) * m->num_charsets);
-        if (!m->charsets)
-                goto_bad;
+       if (!(m->charsets = dm_pool_alloc(scratch, sizeof(*m->charsets) * m->num_charsets)))
+               goto_bad;
 
        _fill_table(m, rx);
-       _create_bitsets(m);
+
+       if (!_create_bitsets(m))
+               goto_bad;
+
        _calc_functions(m);
-       _calc_states(m, rx);
+
+       if (!_calc_states(m, rx))
+               goto_bad;
+
        return m;
 
       bad:
        dm_pool_free(mem, m);
+
        return NULL;
 }
 
@@ -373,14 +400,17 @@ static struct dfa_state *_step_matcher(struct dm_regex *m, int c, struct dfa_sta
         struct dfa_state *ns;
 
        if (!(ns = cs->lookup[(unsigned char) c])) {
-               _calc_state(m, cs, (unsigned char) c);
+               if (!_calc_state(m, cs, (unsigned char) c))
+                        return_NULL;
+
                if (!(ns = cs->lookup[(unsigned char) c]))
                        return NULL;
        }
 
         // yuck, we have to special case the target trans
-        if (ns->final == -1)
-                _calc_state(m, ns, TARGET_TRANS);
+       if ((ns->final == -1) &&
+           !_calc_state(m, ns, TARGET_TRANS))
+                return_NULL;
 
        if (ns->final && (ns->final > *r))
                *r = ns->final;
@@ -433,14 +463,14 @@ struct printer {
         unsigned next_index;
 };
 
-static uint32_t randomise_(uint32_t n)
+static uint32_t _randomise(uint32_t n)
 {
         /* 2^32 - 5 */
         uint32_t const prime = (~0) - 4;
         return n * prime;
 }
 
-static int seen_(struct node_list *n, struct dfa_state *node, uint32_t *i)
+static int _seen(struct node_list *n, struct dfa_state *node, uint32_t *i)
 {
         while (n) {
                 if (n->node == node) {
@@ -456,32 +486,36 @@ static int seen_(struct node_list *n, struct dfa_state *node, uint32_t *i)
 /*
  * Push node if it's not been seen before, returning a unique index.
  */
-static uint32_t push_node_(struct printer *p, struct dfa_state *node)
+static uint32_t _push_node(struct printer *p, struct dfa_state *node)
 {
         uint32_t i;
-        if (seen_(p->pending, node, &i) ||
-            seen_(p->processed, node, &i))
+       struct node_list *n;
+
+        if (_seen(p->pending, node, &i) ||
+            _seen(p->processed, node, &i))
                 return i;
-        else {
-                struct node_list *n = dm_pool_alloc(p->mem, sizeof(*n));
-                assert(n);
-                n->node_id = p->next_index++;
-                n->node = node;
-                n->next = p->pending;
-                p->pending = n;
-                return n->node_id;
-        }
+
+       if (!(n = dm_pool_alloc(p->mem, sizeof(*n))))
+               return_0;
+
+       n->node_id = ++p->next_index; /* start from 1, keep 0 as error code */
+       n->node = node;
+       n->next = p->pending;
+       p->pending = n;
+
+       return n->node_id;
 }
 
 /*
  * Pop the front node, and fill out it's previously assigned index.
  */
-static struct dfa_state *pop_node_(struct printer *p)
+static struct dfa_state *_pop_node(struct printer *p)
 {
         struct dfa_state *node = NULL;
+       struct node_list *n;
 
-        if (p->pending) {
-                struct node_list *n = p->pending;
+       if (p->pending) {
+               n = p->pending;
                 p->pending = n->next;
                 n->next = p->processed;
                 p->processed = n;
@@ -492,22 +526,22 @@ static struct dfa_state *pop_node_(struct printer *p)
         return node;
 }
 
-static uint32_t combine_(uint32_t n1, uint32_t n2)
+static uint32_t _combine(uint32_t n1, uint32_t n2)
 {
-        return ((n1 << 8) | (n1 >> 24)) ^ randomise_(n2);
+        return ((n1 << 8) | (n1 >> 24)) ^ _randomise(n2);
 }
 
-static uint32_t fingerprint_(struct printer *p)
+static uint32_t _fingerprint(struct printer *p)
 {
         int c;
         uint32_t result = 0;
         struct dfa_state *node;
 
-        while ((node = pop_node_(p))) {
-                result = combine_(result, node->final < 0 ? 0 : node->final);
+        while ((node = _pop_node(p))) {
+                result = _combine(result, (node->final < 0) ? 0 : node->final);
                 for (c = 0; c < 256; c++)
-                        result = combine_(result,
-                                          push_node_(p, node->lookup[c]));
+                        result = _combine(result,
+                                          _push_node(p, node->lookup[c]));
         }
 
         return result;
@@ -515,20 +549,27 @@ static uint32_t fingerprint_(struct printer *p)
 
 uint32_t dm_regex_fingerprint(struct dm_regex *regex)
 {
-        uint32_t result;
         struct printer p;
+        uint32_t result = 0;
         struct dm_pool *mem = dm_pool_create("regex fingerprint", 1024);
 
-        _force_states(regex);
+       if (!mem)
+               return_0;
+
+       if (!_force_states(regex))
+               goto_out;
 
-        assert(mem);
         p.mem = mem;
         p.pending = NULL;
         p.processed = NULL;
         p.next_index = 0;
 
-        push_node_(&p, regex->start);
-        result = fingerprint_(&p);
+       if (!_push_node(&p, regex->start))
+               goto_out;
+
+       result = _fingerprint(&p);
+out:
         dm_pool_destroy(mem);
+
         return result;
 }
index ec97c98c70d84ce670857ae89e73cf52746a3f03..00b371e8245183c059c83cebfe4a589d7236761c 100644 (file)
@@ -28,6 +28,7 @@ struct ttree {
        struct node *root;
 };
 
+__attribute__((nonnull(1)))
 static struct node **_lookup_single(struct node **c, unsigned int k)
 {
        while (*c) {
index ec9522bca850806c5dbc52f4509019e689117d5d..8ae4661fbac1c94c9d740f2ca2e3b6354a43d603 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
-# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
 #
 # This file is part of LVM2.
 #
@@ -37,6 +37,8 @@ CLEAN_TARGETS += liblvm.cflow $(LIB_NAME).a
 EXPORTED_HEADER = $(srcdir)/lvm2app.h
 EXPORTED_FN_PREFIX = lvm
 
+LDDEPS += $(top_builddir)/lib/liblvm-internal.a
+
 include $(top_builddir)/make.tmpl
 
 LIBS += $(LVMINTERNAL_LIBS) -ldevmapper
index 317911d9a4ec422e886de3c1fbeb4442cfbd90e6..b7589455f32778764e292b00e1b4f0bce580603e 100644 (file)
@@ -302,6 +302,28 @@ int lvm_config_reload(lvm_t libh);
  */
 int lvm_config_override(lvm_t libh, const char *config_string);
 
+/**
+ * Find a boolean value in the LVM configuration.
+ *
+ * \memberof lvm_t
+ *
+ * This function finds a boolean value associated with a path
+ * in current LVM configuration.
+ *
+ * \param   libh
+ * Handle obtained from lvm_init().
+ *
+ * \param   config_path
+ * A path in LVM configuration
+ *
+ * \param   fail
+ * Value to return if the path is not found.
+ *
+ * \return
+ * boolean value for 'config_path' (success) or the value of 'fail' (error)
+ */
+int lvm_config_find_bool(lvm_t libh, const char *config_path, int fail);
+
 /**
  * Return stored error no describing last LVM API error.
  *
@@ -1321,6 +1343,22 @@ int lvm_lv_remove_tag(lv_t lv, const char *tag);
  */
 struct dm_list *lvm_lv_get_tags(const lv_t lv);
 
+/**
+ * Rename logical volume to new_name.
+ *
+ * \memberof lv_t
+ *
+ * \param   lv
+ * Logical volume handle.
+ *
+ * \param   new_name
+ * New name of logical volume.
+ *
+ * \return
+ * 0 (success) or -1 (failure).
+ *
+ */
+int lvm_lv_rename(lv_t lv, const char *new_name);
 
 /**
  * Resize logical volume to new_size bytes.
@@ -1591,7 +1629,8 @@ typedef enum {
        PERCENT_0 = 0,
        PERCENT_1 = 1000000,
        PERCENT_100 = 100 * PERCENT_1,
-       PERCENT_INVALID = -1
+       PERCENT_INVALID = -1,
+       PERCENT_MERGE_FAILED = -2
 } percent_range_t;
 
 typedef int32_t percent_t;
index 9e1a8ecd87241d81085f0428c2354cc26e694338..01ea0d71118b94e63fcbf0abf15a6b1194834415 100644 (file)
@@ -31,10 +31,13 @@ lvm_t lvm_init(const char *system_dir)
        /* FIXME: logging bound to handle
         */
 
+       if (!udev_init_library_context())
+               stack;
+
        /* create context */
        /* FIXME: split create_toolcontext */
        /* FIXME: make all globals configurable */
-       cmd = create_toolcontext(0, system_dir);
+       cmd = create_toolcontext(0, system_dir, 0, 0);
        if (!cmd)
                return NULL;
 
@@ -69,6 +72,7 @@ lvm_t lvm_init(const char *system_dir)
 void lvm_quit(lvm_t libh)
 {
        destroy_toolcontext((struct cmd_context *)libh);
+       udev_fin_library_context();
 }
 
 int lvm_config_reload(lvm_t libh)
@@ -90,6 +94,11 @@ int lvm_config_override(lvm_t libh, const char *config_settings)
        return 0;
 }
 
+int lvm_config_find_bool(lvm_t libh, const char *config_path, int fail)
+{
+       return find_config_tree_bool((struct cmd_context *)libh, config_path, fail);
+}
+
 int lvm_errno(lvm_t libh)
 {
        return stored_errno();
@@ -117,3 +126,8 @@ const char *lvm_vgname_from_device(lvm_t libh, const char *device)
        struct cmd_context *cmd = (struct cmd_context *)libh;
        return find_vgname_from_pvname(cmd, device);
 }
+
+float lvm_percent_to_float(percent_t v)
+{
+       return percent_to_float(v);
+}
index b77f78cd75cbe0d1fd5841a54f4363e6e9954d22..d47a8578e7654b1b9bac4631d114c4214bda6683 100644 (file)
@@ -62,7 +62,7 @@ struct lvm_property_value lvm_lvseg_get_property(const lvseg_t lvseg,
 uint64_t lvm_lv_is_active(const lv_t lv)
 {
        struct lvinfo info;
-       if (lv_info(lv->vg->cmd, lv, 0, &info, 1, 0) &&
+       if (lv_info(lv->vg->cmd, lv, 0, &info, 0, 0) &&
            info.exists && info.live_table)
                return 1;
        return 0;
@@ -71,7 +71,7 @@ uint64_t lvm_lv_is_active(const lv_t lv)
 uint64_t lvm_lv_is_suspended(const lv_t lv)
 {
        struct lvinfo info;
-       if (lv_info(lv->vg->cmd, lv, 0, &info, 1, 0) &&
+       if (lv_info(lv->vg->cmd, lv, 0, &info, 0, 0) &&
            info.exists && info.suspended)
                return 1;
        return 0;
@@ -110,7 +110,7 @@ static void _lv_set_default_params(struct lvcreate_params *lp,
        lp->zero = 1;
        lp->major = -1;
        lp->minor = -1;
-       lp->activation_monitoring = DEFAULT_DMEVENTD_MONITOR;
+       lp->activate = CHANGE_AY;
        lp->vg_name = vg->name;
        lp->lv_name = lvname; /* FIXME: check this for safety */
        lp->pvh = &vg->pvs;
@@ -123,12 +123,18 @@ static void _lv_set_default_params(struct lvcreate_params *lp,
 }
 
 /* Set default for linear segment specific LV parameters */
-static void _lv_set_default_linear_params(struct cmd_context *cmd,
+static int _lv_set_default_linear_params(struct cmd_context *cmd,
                                          struct lvcreate_params *lp)
 {
-       lp->segtype = get_segtype_from_string(cmd, "striped");
+       if (!(lp->segtype = get_segtype_from_string(cmd, "striped"))) {
+               log_error(INTERNAL_ERROR "Segtype striped not found.");
+               return 0;
+       }
+
        lp->stripes = 1;
        lp->stripe_size = DEFAULT_STRIPESIZE * 2;
+
+       return 1;
 }
 
 /*
@@ -138,7 +144,7 @@ static void _lv_set_default_linear_params(struct cmd_context *cmd,
  */
 lv_t lvm_vg_create_lv_linear(vg_t vg, const char *name, uint64_t size)
 {
-       struct lvcreate_params lp;
+       struct lvcreate_params lp = { 0 };
        uint64_t extents;
        struct lv_list *lvl;
 
@@ -146,15 +152,19 @@ lv_t lvm_vg_create_lv_linear(vg_t vg, const char *name, uint64_t size)
                return NULL;
        if (!vg_check_write_mode(vg))
                return NULL;
-       memset(&lp, 0, sizeof(lp));
-       extents = extents_from_size(vg->cmd, size / SECTOR_SIZE,
-                                   vg->extent_size);
+
+       if (!(extents = extents_from_size(vg->cmd, size / SECTOR_SIZE,
+                                         vg->extent_size))) {
+               log_error("Unable to create LV without size.");
+               return NULL;
+       }
+
        _lv_set_default_params(&lp, vg, name, extents);
-       _lv_set_default_linear_params(vg->cmd, &lp);
+       if (!_lv_set_default_linear_params(vg->cmd, &lp))
+               return_NULL;
        if (!lv_create_single(vg, &lp))
-               return NULL;
-       lvl = find_lv_in_vg(vg, name);
-       if (!lvl)
+               return_NULL;
+       if (!(lvl = find_lv_in_vg(vg, name)))
                return NULL;
        return (lv_t) lvl->lv;
 }
@@ -269,12 +279,12 @@ lv_t lvm_lv_from_uuid(vg_t vg, const char *uuid)
                log_errno (EINVAL, "Invalid UUID string length");
                return NULL;
        }
-       if (strlen(uuid) >= ID_LEN) {
-               if (!id_read_format(&id, uuid)) {
-                       log_errno(EINVAL, "Invalid UUID format");
-                       return NULL;
-               }
+
+       if (!id_read_format(&id, uuid)) {
+               log_errno(EINVAL, "Invalid UUID format.");
+               return NULL;
        }
+
        dm_list_iterate_items(lvl, &vg->lvs) {
                if (id_equal(&vg->id, &lvl->lv->lvid.id[0]) &&
                    id_equal(&id, &lvl->lv->lvid.id[1]))
@@ -282,6 +292,16 @@ lv_t lvm_lv_from_uuid(vg_t vg, const char *uuid)
        }
        return NULL;
 }
+
+int lvm_lv_rename(lv_t lv, const char *new_name)
+{
+       if (!lv_rename(lv->vg->cmd, lv, new_name)) {
+               log_verbose("LV Rename failed.");
+               return -1;
+       }
+       return 0;
+}
+
 int lvm_lv_resize(const lv_t lv, uint64_t new_size)
 {
        /* FIXME: add lv resize code here */
index 62fef6124425bec5c425762eb404538f382bc00a..0a0ea12ebec88a703285f4e7999fa53f6761728a 100644 (file)
@@ -50,35 +50,30 @@ struct lvm_property_value get_property(const pv_t pv, const vg_t vg,
                                       const pvseg_t pvseg, const char *name)
 {
        struct lvm_property_type prop;
-       struct lvm_property_value v;
+       struct lvm_property_value v = { 0 };
 
        prop.id = name;
+
        if (pv) {
-               if (!pv_get_property(pv, &prop)) {
-                       v.is_valid = 0;
+               if (!pv_get_property(pv, &prop))
                        return v;
-               }
        } else if (vg) {
-               if (!vg_get_property(vg, &prop)) {
-                       v.is_valid = 0;
+               if (!vg_get_property(vg, &prop))
                        return v;
-               }
        } else if (lv) {
-               if (!lv_get_property(lv, &prop)) {
-                       v.is_valid = 0;
+               if (!lv_get_property(lv, &prop))
                        return v;
-               }
        } else if (lvseg) {
-               if (!lvseg_get_property(lvseg, &prop)) {
-                       v.is_valid = 0;
+               if (!lvseg_get_property(lvseg, &prop))
                        return v;
-               }
        } else if (pvseg) {
-               if (!pvseg_get_property(pvseg, &prop)) {
-                       v.is_valid = 0;
+               if (!pvseg_get_property(pvseg, &prop))
                        return v;
-               }
+       } else {
+               log_errno(EINVAL, "Invalid NULL handle passed to library function.");
+               return v;
        }
+
        v.is_settable = prop.is_settable;
        v.is_string = prop.is_string;
        v.is_integer = prop.is_integer;
index 4fe2d3ed7f8e2e0af71ed21048866936afbc65c8..90edaed5a3475d6ee6cb30765495f6c4318b5ab8 100644 (file)
@@ -107,12 +107,12 @@ pv_t lvm_pv_from_uuid(vg_t vg, const char *uuid)
                log_errno (EINVAL, "Invalid UUID string length");
                return NULL;
        }
-       if (strlen(uuid) >= ID_LEN) {
-               if (!id_read_format(&id, uuid)) {
-                       log_errno(EINVAL, "Invalid UUID format");
-                       return NULL;
-               }
+
+       if (!id_read_format(&id, uuid)) {
+               log_errno(EINVAL, "Invalid UUID format.");
+               return NULL;
        }
+
        dm_list_iterate_items(pvl, &vg->pvs) {
                if (id_equal(&id, &pvl->pv->id))
                        return pvl->pv;
index f087ba4356241647c3e3106b39d9de441a7dc438..405a91a1044e7316aa2fccdc121cf0ae75b93c44 100644 (file)
@@ -56,7 +56,7 @@ vg_t lvm_vg_create(lvm_t libh, const char *vg_name)
        vg = vg_create((struct cmd_context *)libh, vg_name);
        /* FIXME: error handling is still TBD */
        if (vg_read_error(vg)) {
-               free_vg(vg);
+               release_vg(vg);
                return NULL;
        }
        vg->open_mode = 'w';
@@ -79,7 +79,7 @@ int lvm_vg_extend(vg_t vg, const char *device)
        }
 
        pvcreate_params_set_defaults(&pp);
-       if (!vg_extend(vg, 1, (char **) &device, &pp)) {
+       if (!vg_extend(vg, 1, &device, &pp)) {
                unlock_vg(vg->cmd, VG_ORPHANS);
                return -1;
        }
@@ -98,7 +98,7 @@ int lvm_vg_reduce(vg_t vg, const char *device)
        if (!vg_check_write_mode(vg))
                return -1;
 
-       if (!vg_reduce(vg, (char *)device))
+       if (!vg_reduce(vg, device))
                return -1;
        return 0;
 }
@@ -147,6 +147,7 @@ int lvm_vg_write(vg_t vg)
        if (! dm_list_empty(&vg->removed_pvs)) {
                dm_list_iterate_items(pvl, &vg->removed_pvs) {
                        pv_write_orphan(vg->cmd, pvl->pv);
+                       pv_set_fid(pvl->pv, NULL);
                        /* FIXME: do pvremove / label_remove()? */
                }
                dm_list_init(&vg->removed_pvs);
@@ -159,9 +160,9 @@ int lvm_vg_write(vg_t vg)
 int lvm_vg_close(vg_t vg)
 {
        if (vg_read_error(vg) == FAILED_LOCKING)
-               free_vg(vg);
+               release_vg(vg);
        else
-               unlock_and_free_vg(vg->cmd, vg, vg->name);
+               unlock_and_release_vg(vg->cmd, vg, vg->name);
        return 0;
 }
 
@@ -196,7 +197,7 @@ vg_t lvm_vg_open(lvm_t libh, const char *vgname, const char *mode,
        vg = vg_read((struct cmd_context *)libh, vgname, NULL, internal_flags);
        if (vg_read_error(vg)) {
                /* FIXME: use log_errno either here in inside vg_read */
-               free_vg(vg);
+               release_vg(vg);
                return NULL;
        }
        /* FIXME: combine this with locking ? */
index 806f77aac0090e78d51e1073e34f8d2b42599521..8b56f013bd91ad87f612645f1adc6209b4712737 100644 (file)
@@ -1,7 +1,7 @@
 # @configure_input@
 #
 # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
-# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
 #
 # This file is part of LVM2.
 #
@@ -28,6 +28,7 @@ LN_S = @LN_S@
 SED = @SED@
 CFLOW_CMD = @CFLOW_CMD@
 AWK = @AWK@
+PYTHON = @PYTHON@
 
 LIBS = @LIBS@
 # Extra libraries always linked with static binaries
@@ -35,10 +36,11 @@ STATIC_LIBS = $(SELINUX_LIBS) $(UDEV_LIBS)
 DEFS += @DEFS@
 CFLAGS += @CFLAGS@
 CLDFLAGS += @CLDFLAGS@
+ELDFLAGS += @ELDFLAGS@
 LDDEPS += @LDDEPS@
 LDFLAGS += @LDFLAGS@
 LIB_SUFFIX = @LIB_SUFFIX@
-LVMINTERNAL_LIBS = -llvm-internal $(DL_LIBS)
+LVMINTERNAL_LIBS = -llvm-internal $(DAEMON_LIBS) $(UDEV_LIBS) $(DL_LIBS)
 DL_LIBS = @DL_LIBS@
 PTHREAD_LIBS = @PTHREAD_LIBS@
 READLINE_LIBS = @READLINE_LIBS@
@@ -50,6 +52,8 @@ TESTING = @TESTING@
 prefix = @prefix@
 exec_prefix = @exec_prefix@
 udev_prefix = @udev_prefix@
+sysconfdir = @sysconfdir@
+rootdir = $(DESTDIR)/
 bindir = $(DESTDIR)@bindir@
 confdir = $(DESTDIR)@CONFDIR@/lvm
 includedir = $(DESTDIR)@includedir@
@@ -57,15 +61,18 @@ libdir = $(DESTDIR)@libdir@
 usrlibdir = $(DESTDIR)@usrlibdir@
 sbindir = $(DESTDIR)@sbindir@
 usrsbindir = $(DESTDIR)@usrsbindir@
-datarootdir = $(DESTDIR)@datarootdir@
-infodir = $(datarootdir)/info
-mandir = $(datarootdir)/man
+datarootdir = @datarootdir@
+infodir = $(DESTDIR)@infodir@
+mandir = $(DESTDIR)@mandir@
 localedir = $(DESTDIR)@LOCALEDIR@
 staticdir = $(DESTDIR)@STATICDIR@
 udevdir = $(DESTDIR)@udevdir@
 pkgconfigdir = $(usrlibdir)/pkgconfig
-initdir = $(DESTDIR)@sysconfdir@/rc.d/init.d
-ocf_scriptdir = $(DESTDIR)@prefix@/usr/lib/ocf/resource.d/lvm2
+initdir = $(DESTDIR)$(sysconfdir)/rc.d/init.d
+systemd_unit_dir = $(DESTDIR)@systemdsystemunitdir@
+systemd_generator_dir = $(DESTDIR)@systemdutildir@/system-generators
+tmpfiles_dir = $(DESTDIR)@tmpfilesdir@
+ocf_scriptdir = $(DESTDIR)@OCFDIR@
 
 USRLIB_RELPATH = $(shell echo $(abspath $(usrlibdir) $(libdir)) | \
   $(AWK) -f $(top_srcdir)/scripts/relpath.awk)
@@ -104,20 +111,24 @@ INSTALL_PROGRAM = $(INSTALL) $(M_INSTALL_PROGRAM) $(STRIP)
 INSTALL_DATA = $(INSTALL) -p $(M_INSTALL_DATA)
 INSTALL_WDATA = $(INSTALL) -p -m 644
 
-INSTALL_DIR = $(INSTALL) -m 0755 -d
-INSTALL_ROOT_DIR = $(INSTALL) -m 0700 -d
-INSTALL_ROOT_DATA = $(INSTALL) -m 0600
+INSTALL_DIR = $(INSTALL) -m 755 -d
+INSTALL_ROOT_DIR = $(INSTALL) -m 700 -d
+INSTALL_ROOT_DATA = $(INSTALL) -m 600
 INSTALL_SCRIPT = $(INSTALL) -p $(M_INSTALL_PROGRAM)
 
 .SUFFIXES: .c .d .o .so .a .po .pot .mo .dylib
 
-CFLAGS += -fPIC -Wall -Wundef -Wshadow -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline -Wmissing-noreturn -Wformat-security -Wredundant-decls
+WFLAGS += -Wall -Wundef -Wshadow -Wcast-align -Wwrite-strings \
+ -Wmissing-prototypes -Wmissing-declarations -Wnested-externs \
+ -Winline -Wmissing-noreturn -Wformat-security -Wredundant-decls \
+ -Wpointer-arith
 
-#CFLAGS += -W -Wconversion -Wpointer-arith -Wbad-function-cast -Wcast-qual
-#CFLAGS += -pedantic -std=gnu99
-#CFLAGS += -DDEBUG_CRC32
+#WFLAGS += -W -Wconversion -Wbad-function-cast -Wcast-qual
+#WFLAGS += -pedantic -std=gnu99
+#DEFS += -DDEBUG_CRC32
 
-CFLAGS += @COPTIMISE_FLAG@
+CFLAGS += -fPIC  @COPTIMISE_FLAG@
+LDFLAGS += @COPTIMISE_FLAG@
 
 ifeq ("@DEBUG@", "yes")
   CFLAGS += -g -fno-omit-frame-pointer
@@ -135,6 +146,10 @@ endif
 LDFLAGS += -L$(top_builddir)/libdm -L$(top_builddir)/lib
 CLDFLAGS += -L$(top_builddir)/libdm -L$(top_builddir)/lib
 
+DAEMON_LIBS = -ldaemonclient
+LDFLAGS += -L$(top_builddir)/libdaemon/client
+CLDFLAGS += -L$(top_builddir)/libdaemon/client
+
 ifeq ("@DMEVENTD@", "yes")
   LDFLAGS += -L$(top_builddir)/daemons/dmeventd
   CLDFLAGS += -L$(top_builddir)/daemons/dmeventd
@@ -148,7 +163,11 @@ ifeq ("@DM_IOCTLS@", "yes")
   DEFS += -DDM_IOCTLS
 endif
 
+# Combination of DEBUG_POOL and DEBUG_ENFORCE_POOL_LOCKING is not suppored.
 #DEFS += -DDEBUG_POOL
+# Default pool locking is using the crc checksum. With mprotect memory
+# enforcing compilation faulty memory write could be easily found.
+#DEFS += -DDEBUG_ENFORCE_POOL_LOCKING
 #DEFS += -DBOUNDS_CHECK
 
 #CFLAGS += -pg
@@ -178,7 +197,8 @@ POTFILES = $(SOURCES:%.c=%.pot)
 .PHONY: all pofile distclean clean cleandir cflow device-mapper
 .PHONY: install install_cluster install_device-mapper install_lvm2
 .PHONY: install_lib_shared install_dm_plugin install_lvm2_plugin
-.PHONY: install_ocf
+.PHONY: install_ocf help
+.PHONY: python_bindings install_python_bindings
 .PHONY: $(SUBDIRS) $(SUBDIRS.install) $(SUBDIRS.clean) $(SUBDIRS.distclean)
 .PHONY: $(SUBDIRS.pofile) $(SUBDIRS.install_cluster) $(SUBDIRS.cflow)
 .PHONY: $(SUBDIRS.device-mapper) $(SUBDIRS.install-device-mapper)
@@ -296,14 +316,14 @@ endif
 $(TARGETS): $(OBJECTS)
 
 %.o: %.c
-       $(CC) -c $(INCLUDES) $(DEFS) $(CFLAGS) $< -o $@
+       $(CC) -c $(INCLUDES) $(DEFS) $(WFLAGS) $(CFLAGS) $< -o $@
 
 %.pot: %.c Makefile
        $(CC) -E $(INCLUDES) -include $(top_srcdir)/include/pogen.h \
-               $(DEFS) $(CFLAGS) $< > $@
+               $(DEFS) $(WFLAGS) $(CFLAGS) $< > $@
 
 %.so: %.o
-       $(CC) -c $(INCLUDES) $(DEFS) $(CFLAGS) $(CLDFLAGS) $< $(LIBS) -o $@
+       $(CC) -c $(CFLAGS) $(CLDFLAGS) $< $(LIBS) -o $@
 
 ifneq (,$(LIB_SHARED))
 
@@ -348,7 +368,7 @@ $(LIB_STATIC): $(OBJECTS)
        set -e; \
        FILE=`echo $@ | sed 's/\\//\\\\\\//g;s/\\.d//g'`; \
        DEPS=`echo $(DEPS) | sed -e 's/\\//\\\\\\//g'`; \
-       $(CC) -MM $(INCLUDES) $(DEFS) $(CFLAGS) -o $@ $<; \
+       $(CC) -MM $(INCLUDES) $(DEFS) -o $@ $<; \
        sed -i "s/\(.*\)\.o[ :]*/$$FILE.o $$FILE.d $$FILE.pot: $$DEPS /g" $@; \
        [ -s $@ ] || $(RM) $@
 
@@ -358,20 +378,21 @@ $(LIB_STATIC): $(OBJECTS)
 cleandir:
        $(RM) $(OBJECTS) $(TARGETS) $(CLEAN_TARGETS) $(CLEAN_CFLOW) $(LDDEPS) \
          $(POTFILES) $(SOURCES:%.c=%.d) $(SOURCES:%.c=%.gcno) $(SOURCES:%.c=%.gcda) \
-         $(SOURCES2:%.c=%.o) $(SOURCES2:%.c=%.d) $(SOURCES2:%.c=%.gcno) $(SOURCES2:%.c=%.gcda)
+         $(SOURCES2:%.c=%.o) $(SOURCES2:%.c=%.d) $(SOURCES2:%.c=%.gcno) $(SOURCES2:%.c=%.gcda) \
+         .exported_symbols_generated core
 
 clean: $(SUBDIRS.clean) cleandir
 
 distclean: cleandir $(SUBDIRS.distclean)
        test -z "$(DISTCLEAN_DIRS)" || $(RM) -r $(DISTCLEAN_DIRS)
-       $(RM) $(DISTCLEAN_TARGETS) Makefile core
+       $(RM) $(DISTCLEAN_TARGETS) Makefile 
 
 .exported_symbols_generated: $(EXPORTED_HEADER) .exported_symbols
        set -e; \
        ( cat $(srcdir)/.exported_symbols; \
          if test x$(EXPORTED_HEADER) != x; then \
-               $(CC) -E -P $(INCLUDES) $(DEFS) $(CFLAGS) $(EXPORTED_HEADER) | \
-               $(SED) -ne "/^typedef|}/!s/.*[ \*]\(\$(EXPORTED_FN_PREFIX)_[a-z0-9_]*\)(.*/\1/p"; \
+               $(CC) -E -P $(INCLUDES) $(DEFS) $(EXPORTED_HEADER) | \
+               $(SED) -ne "/^typedef|}/!s/.*[ \*]\(\$(EXPORTED_FN_PREFIX)_[a-z0-9_]*\)(.*/\1/p"; \
          fi \
        ) > $@
 
@@ -380,7 +401,8 @@ distclean: cleandir $(SUBDIRS.distclean)
                 sed "s/^/              /;s/$$/;/" < $<; \
                 echo " local:"; echo "         *;"; echo "};") > $@
 
-ifeq (,$(findstring $(MAKECMDGOALS),cscope.out cflow clean distclean lcov))
+ifeq (,$(findstring $(MAKECMDGOALS),cscope.out cflow clean distclean lcov \
+ help check check_local check_cluster check_lvmetad))
     ifdef SOURCES
        -include $(SOURCES:.c=.d)
     endif
index 2506fbd0db24d077e1a0152067981e0261dc8073..8be34c39fcdecd118f01e485d380480ca0fbfa23 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
-# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
 #
 # This file is part of LVM2.
 #
@@ -22,12 +22,24 @@ else
 FSADMMAN =
 endif
 
+ifeq ("@BLKDEACTIVATE@", "yes")
+BLKDEACTIVATEMAN = blkdeactivate.8
+else
+BLKDEACTIVATEMAN =
+endif
+
 ifeq ("@DMEVENTD@", "yes")
 DMEVENTDMAN = dmeventd.8
 else
 DMEVENTDMAN =
 endif
 
+ifeq ("@BUILD_LVMETAD@", "yes")
+LVMETAD = lvmetad.8
+else
+LVMETAD =
+endif
+
 MAN5=lvm.conf.5
 MAN8=lvchange.8 lvconvert.8 lvcreate.8 lvdisplay.8 lvextend.8 lvm.8 \
        lvmchange.8 lvmconf.8 lvmdiskscan.8 lvmdump.8 lvmsadc.8 lvmsar.8 \
@@ -36,7 +48,7 @@ MAN8=lvchange.8 lvconvert.8 lvcreate.8 lvdisplay.8 lvextend.8 lvm.8 \
        pvresize.8 pvs.8 pvscan.8 vgcfgbackup.8 vgcfgrestore.8 vgchange.8 \
        vgck.8 vgcreate.8 vgconvert.8 vgdisplay.8 vgexport.8 vgextend.8 \
        vgimport.8 vgimportclone.8 vgmerge.8 vgmknodes.8 vgreduce.8 vgremove.8 \
-       vgrename.8 vgs.8 vgscan.8 vgsplit.8 $(FSADMMAN)
+       vgrename.8 vgs.8 vgscan.8 vgsplit.8 $(FSADMMAN) $(BLKDEACTIVATEMAN) $(LVMETAD)
 
 ifneq ("@CLVMD@", "none")
   MAN8CLUSTER=clvmd.8
@@ -51,7 +63,7 @@ MAN8DM=dmsetup.8 $(DMEVENTDMAN)
 MAN5DIR=$(mandir)/man5
 MAN8DIR=$(mandir)/man8
 
-CLEAN_TARGETS=$(MAN5) $(MAN8) $(MAN8CLUSTER) $(FSADMMAN) $(DMEVENTDMAN) $(MAN8DM)
+CLEAN_TARGETS=$(MAN5) $(MAN8) $(MAN8CLUSTER) $(FSADMMAN) $(BLKDEACTIVATEMAN) $(DMEVENTDMAN) $(MAN8DM)
 DISTCLEAN_TARGETS=fsadm.8 clvmd.8 cmirrord.8 dmeventd.8
 
 include $(top_builddir)/make.tmpl
@@ -60,7 +72,7 @@ ifneq ("@CLVMD@", "none")
   install: install_cluster
 endif
 
-all: man
+all: man device-mapper
 
 .PHONY: man install_man5 install_man8
 
@@ -68,12 +80,12 @@ device-mapper: $(MAN8DM)
 
 man: $(MAN5) $(MAN8) $(MAN8CLUSTER)
 
-$(MAN5) $(MAN8) $(MAN8CLUSTER):        Makefile
+$(MAN5) $(MAN8) $(MAN8DM) $(MAN8CLUSTER):      Makefile
 
 %: %.in
        @case "$@" in \
          */*) ;; \
-         *) echo "Creating $@" ; $(SED) -e "s+#VERSION#+$(LVM_VERSION)+;s+#DEFAULT_SYS_DIR#+$(DEFAULT_SYS_DIR)+;s+#DEFAULT_ARCHIVE_DIR#+$(DEFAULT_ARCHIVE_DIR)+;s+#DEFAULT_BACKUP_DIR#+$(DEFAULT_BACKUP_DIR)+;s+#DEFAULT_CACHE_DIR#+$(DEFAULT_CACHE_DIR)+;s+#DEFAULT_LOCK_DIR#+$(DEFAULT_LOCK_DIR)+" $< > $@ ;; \
+         *) echo "Creating $@" ; $(SED) -e "s+#VERSION#+$(LVM_VERSION)+;s+#DEFAULT_SYS_DIR#+$(DEFAULT_SYS_DIR)+;s+#DEFAULT_ARCHIVE_DIR#+$(DEFAULT_ARCHIVE_DIR)+;s+#DEFAULT_BACKUP_DIR#+$(DEFAULT_BACKUP_DIR)+;s+#DEFAULT_CACHE_DIR#+$(DEFAULT_CACHE_DIR)+;s+#DEFAULT_LOCK_DIR#+$(DEFAULT_LOCK_DIR)+;s+#CLVMD_PATH#+@CLVMD_PATH@+;s+#LVM_PATH#+@LVM_PATH@+;s+#DEFAULT_RUN_DIR#+@DEFAULT_RUN_DIR@+;" $< > $@ ;; \
        esac
 
 install_man5: $(MAN5)
diff --git a/man/blkdeactivate.8.in b/man/blkdeactivate.8.in
new file mode 100644 (file)
index 0000000..6e566c8
--- /dev/null
@@ -0,0 +1,72 @@
+.TH "BLKDEACTIVATE" "8" "LVM TOOLS #VERSION#" "Red Hat, Inc" "\""
+.SH "NAME"
+blkdeactivate \- utility to deactivate block devices
+.SH SYNOPSIS
+.B blkdeactivate
+.RI [ options ]
+.RI [ device... ]
+.sp
+.SH DESCRIPTION
+blkdeactivate utility deactivates block devices. If a device
+is mounted, the utility can unmount it automatically before
+trying to deactivate. The utility currently supports
+\fIdevice-mapper\fP devices, including \fILVM\fP volumes.
+LVM volumes are handled directly using the \fIlvm\fP command.
+Other device-mapper based devices are handled using the
+\fIdmsetup\fP command.
+.SH OPTIONS
+.IP "\fB\-h, \-\-help\fP"
+Display the help text.
+.IP "\fB\-u, \-\-umount\fP"
+Unmount a mounted device before trying to deactivate it.
+Without this option used, a device that is mounted is not deactivated.
+.IP "\fB\-d, \-\-dmoption\fP \fIdm_options\fP"
+Comma separated list of device-mapper specific options.
+.IP "\fB\-l, \-\-lvmoption\fP \fIlvm_options\fP"
+Comma separated list of LVM specific options.
+.SH DM_OPTIONS
+.IP "\fBretry\fP"
+Retry removal several times in case of failure.
+.IP "\fBforce\fP"
+Force device removal. See \fBdmsetup\fP(8) for more information.
+.SH LVM_OPTIONS
+.IP "\fBretry\fP"
+Retry removal several times in case of failure.
+.IP "\fBwholevg\fP"
+Deactivate the whole LVM Volume Group when processing a Logical Volume.
+Deactivating Volume Group as a whole takes less time than deactivating
+each Logical Volume separately.
+
+.SH EXAMPLES
+.sp
+Deactivate all supported block devices found in the system. If a device
+is mounted, skip its deactivation.
+.sp
+.B blkdeactivate
+
+Deactivate all supported block devices found in the system. If a device
+is mounted, unmount it first if possible.
+.sp
+.B blkdeactivate \-u
+
+Deactivate supplied device together with all its holders. If any of the
+devices processed is mounted, unmount it first if possible.
+.sp
+.B blkdeactivate \-u /dev/vg/lvol0
+
+Deactivate all supported block devices found in the system. Retry deactivation
+of device-mapper devices in case the deactivation fails. Deactivate the whole
+Volume Group at once when processing an LVM Logical Volume.
+.sp
+.B blkdeactivate \-u -d retry -l wholevg
+
+Deactivate all supported block devices found in the system. Retry deactivation
+of device-mapper devices in case the deactivation fails and force removal.
+.sp
+.B blkdeactivate -d force,retry
+
+.SH SEE ALSO
+.BR lsblk (8)
+.BR umount (8)
+.BR dmsetup (8)
+.BR lvm (8)
index 53a9113a819bd7ce7d344b0823ca667853fc3a7b..2d7b06b1235df441cfb51f0580166514d7dd78ce 100644 (file)
 clvmd \- cluster LVM daemon
 .SH SYNOPSIS
 .B clvmd
-[\-d [<value>]] [\-C] [\-h]
-[\-R]
-[\-S]
-[\-t <timeout>]
-[\-T <start timeout>]
-[\-V]
+.RB [ \-d
+.RI [< value >]
+.RB [ \-C ]]
+.RB [ \-E
+.RI < "lock uuid" >]
+.RB [ \-f ]
+.RB [ \-h ]
+.RB [ \-I
+.IR "cluster_manager" ]
+.RB [ \-R ]
+.RB [ \-S ]
+.RB [ \-t
+.RI < timeout >]
+.RB [ \-T
+.RI < "start timeout" >]
+.RB [ \-V ]
 .SH DESCRIPTION
 clvmd is the daemon that distributes LVM metadata updates around a cluster.
-It must be running on all nodes in the cluster and will give an error 
+It must be running on all nodes in the cluster and will give an error
 if a node in the cluster does not have this daemon running.
 .SH OPTIONS
 .TP
-.I \-d [<value>]
+.BR \-d [< \fIvalue >]
 Enable debug logging. Value can be 0, 1 or 2.
 .br
-0 disables debug logging in a running clvmd
+0 disables debug logging
 .br
-1 sends debug logs to stderr (clvmd will not fork in this case)
+1 sends debug logs to stderr (implies \fB\-f\fP option)
 .br
 2 sends debug logs to syslog
 .br
-If 
-.B -d 
-is specified without a value then 1 is assumed if you are starting a
-new clvmd, 2 if you are enabling debug in a running clvmd.
+If
+.B \-d
+is specified without a value then 1 is assumed.
 .TP
-.I \-C
-Only valid if 
-.B -d 
+.B \-C
+Only valid if
+.B \-d
 is also specified. Tells all clvmds in a cluster to enable/disable debug logging.
 Without this switch, only the local clvmd will change its debug level to that
-given with 
-.B -d.
+given with
+.B \-d
+.
 .br
 This does not work correctly if specified on the command-line that starts clvmd.
-If you want to start clvmd 
-.B and 
+If you want to start clvmd
+.B and
 enable cluster-wide logging then the command needs to be issued twice, eg:
 .br
-clvmd
+.B clvmd
 .br
-clvmd -d2
+.B clvmd -d2
 .br
 .TP
-.I \-t <timeout>
+.BR \-E < "\fIlock uuid" >
+Pass lock uuid to be reacquired exclusively when clvmd is restarted.
+.TP
+.B \-f
+Don't fork, run in the foreground.
+.TP
+.B \-h
+Show help information.
+.TP
+.B \-I \fIcluster manager
+Selects the cluster manager to use for locking and internal communications,
+the available managers will be listed as part of the \fBclvmd -h\fP output.
+clvmd will use the first cluster manager that succeeds, and it checks them
+in the order cman,corosync,openais. As it is quite possible to have
+(eg) corosync and cman available on the same system you might have to
+manually specify this option to override the search.
+.TP
+.B \-R
+Tells all the running clvmds in the cluster to reload their device cache and
+re-read the lvm configuration file. This command should be run whenever the
+devices on a cluster system are changed.
+.TP
+.B \-S
+Tells the running clvmd to exit and reexecute itself, for example at the
+end of a package upgrade.  The new instance is instructed to reacquire
+any locks in the same state as they were previously held.  (Alternative
+methods of restarting the daemon have the side effect of changing
+exclusive LV locks into shared locks.)
+.TP
+.BR \-t < \fItimeout >
 Specifies the timeout for commands to run around the cluster. This should not
 be so small that commands with many disk updates to do will fail, so you
-may need to increase this on systems with very large disk farms. 
+may need to increase this on systems with very large disk farms.
 The default is 30 seconds.
 .TP
-.I \-T <start timeout>
-Specifies the timeout for clvmd daemon startup. If the daemon does not report 
-that it has started up within this time then the parent command will exit with 
-status of 5. This does NOT mean that clvmd has not started! What it means is 
-that the startup of clvmd has been delayed for some reason; the most likely 
-cause of this is an inquorate cluster though it could be due to locking 
-latencies on a cluster with large numbers of logical volumes. If you get the 
+.BR \-T < "\fIstart timeout" >
+Specifies the timeout for clvmd daemon startup. If the daemon does not report
+that it has started up within this time then the parent command will exit with
+status of 5. This does NOT mean that clvmd has not started! What it means is
+that the startup of clvmd has been delayed for some reason; the most likely
+cause of this is an inquorate cluster though it could be due to locking
+latencies on a cluster with large numbers of logical volumes. If you get the
 return code of 5 it is usually not necessary to restart clvmd - it will start
 as soon as that blockage has cleared. This flag is to allow startup scripts
 to exit in a timely fashion even if the cluster is stalled for some reason.
@@ -70,27 +109,17 @@ sensible.
 .br
 This timeout will be ignored if you start clvmd with the -d switch.
 .TP
-.I \-R
-Tells all the running clvmds in the cluster to reload their device cache and
-re-read the lvm configuration file. This command should be run whenever the
-devices on a cluster system are changed.
-.TP
-.I \-S
-Tells the running clvmd to exit and reexecute itself, for example at the
-end of a package upgrade.  The new instance is instructed to reacquire
-any locks in the same state as they were previously held.  (Alternative
-methods of restarting the daemon have the side effect of changing
-exclusive LV locks into shared locks.)
+.B \-V
+Display the version of the cluster LVM daemon.
+
+.SH ENVIRONMENT VARIABLES
 .TP
-.I \-I
-Selects the cluster manager to use for locking and internal communications,
-the available managers will be listed as part of the 'clvmd -h' output.
-clvmd will use the first cluster manager that succeeds, and it checks them
-in the order cman,gulm,corosync,openais. As it is quite possible to have
-(eg) corosync and cman available on the same system you might have to
-manually specify this option to override the search.
+.B LVM_CLVMD_BINARY
+The CLVMD binary to use when clmvd restart is requested.
+Defaults to #CLVMD_PATH#.
 .TP
-.I \-V
-Display the version of the cluster LVM daemon.
+.B LVM_BINARY
+The LVM2 binary to use. Defaults to #LVM_PATH#.
+
 .SH SEE ALSO
 .BR lvm (8)
index cc5a74106f27dd27e0db8e1fcec5163d3a9e0ed1..e742a61d250d42ff3151d2e783039d496d28f3a6 100644 (file)
@@ -3,11 +3,12 @@
 dmeventd \- Device-mapper event daemon
 .SH SYNOPSIS
 .B dmeventd
-[\-d]
-[\-f]
-[\-h]
-[\-V]
-[\-?]
+.RB [ \-d " [" -d " [" -d ]]]
+.RB [ \-f ]
+.RB [ \-h ]
+.RB [ \-R ]
+.RB [ \-V ]
+.RB [ \-? ]
 .SH DESCRIPTION
 dmeventd is the event monitoring daemon for device-mapper devices.
 Library plugins can register and carry out actions triggered when
@@ -18,25 +19,39 @@ LVM PLUGINS
 .I Mirror
 Attempts to handle device failure automatically.  See \fBlvm.conf\fP(5).
 .TP
+.I Raid
+Attempts to handle device failure automatically.  See \fBlvm.conf\fP(5).
+.TP
 .I Snapshot
 Monitors how full a snapshot is becoming and emits a warning to
 syslog when it exceeds 80% full.
 The warning is repeated when 85%, 90% and 95% of the snapshot is filled.
 See \fBlvm.conf\fP(5).
+.TP
+.I Thin
+Monitors how full a thin pool is becoming and emits a warning to
+syslog when it exceeds 80% full.
+The warning is repeated when 85%, 90% and 95% of the thin pool is filled.
+See \fBlvm.conf\fP(5).
 .SH OPTIONS
 .TP
-.I \-d
+.B \-d
 Repeat from 1 to 3 times (-d, -dd, -ddd) to increase the detail of
 debug messages sent to syslog.
 Each extra d adds more debugging information.
 .TP
-.I \-f
+.B \-f
 Don't fork, run in the foreground.
 .TP
-.I \-h, \-?
+.BR \-h ", " \-?
 Show help information.
 .TP
-.I \-V
+.B \-R
+Replace a running dmeventd instance. The running dmeventd must be version
+2.02.77 or newer. The new dmeventd instance will obtain a list of devices and
+events to monitor from the currently running daemon.
+.TP
+.B \-V
 Show version of dmeventd.
 
 .SH SEE ALSO
index 68e9819904452a1cbe520283d6e76f8633f39b56..a4eac1e1cf090a89d6a4de118b47cc7f6b5cbd63 100644 (file)
 dmsetup \- low level logical volume management
 .SH SYNOPSIS
 .ad l
+.B dmsetup clear
+.I device_name
+.br
+.B dmsetup create
+.I device_name
+.RB [ \-u
+.IR uuid ]
+.RB [ \-\-notable | \-\-table
+.RI < table >|
+.RS
+.IR table_file ]
+.RB [{ \-\-addnodeoncreate | \-\-addnodeonresume }]
+.RB [ \-\-readahead
+.RI [ \+ ]< sectors >| auto | none ]
+.RE
+.br
+.B dmsetup deps
+.RB [ \-o
+.IR options ]
+.RI [ device_name ]
+.br
 .B dmsetup help
-.I [-c|-C|--columns]
+.RB [ \-c | \-C | \-\-columns ]
+.br
+.B dmsetup info
+.RI [ device_name ]
+.br
+.B dmsetup info
+.BR \-c | \-C | \-\-columns
+.RB [ \-\-noheadings ]
+.RB [ \-\-separator
+.IR separator ]
+.RS
+.RB [ \-o
+.IR fields ]
+.RB [ \-O | \-\-sort
+.IR sort_fields ]
+.RI [ device_name ]
+.RE
 .br
-.B dmsetup create 
-.I device_name [-u uuid] [--notable | --table <table> | table_file]
+.B dmsetup load
+.I device_name
+.RB [ \-\-table
+.RI < table >| table_file ]
 .br
-.B dmsetup remove
-.I [-f|--force] device_name
+.B dmsetup ls
+.RB [ \-\-target
+.IR target_type ]
+.RB [ \-\-exec
+.IR command ]
+.RB [ \-\-tree ]
+.RB [ \-o
+.IR options ]
+.RE
 .br
-.B dmsetup remove_all
-.I [-f|--force]
+.B dmsetup message
+.I device_name sector message
 .br
-.B dmsetup suspend
-.I [--nolockfs] [--noflush] device_name
+.B dmsetup mknodes
+.RI [ device_name ]
 .br
-.B dmsetup resume
+.B dmsetup mangle
+.RI [ device_name ]
+.br
+.B dmsetup reload
 .I device_name
+.RB [ \-\-table
+.RI < table >| table_file ]
 .br
-.B dmsetup load
-.I device_name [--table <table> | table_file]
+.B dmsetup wipe_table
+.I device_name
 .br
-.B dmsetup clear
+.B dmsetup remove
+.RB [ \-f | \-\-force ]
+.RB [ \-\-retry ]
 .I device_name
 .br
-.B dmsetup reload
-.I device_name [--table <table> | table_file]
+.B dmsetup remove_all
+.RB [ \-f | \-\-force ]
 .br
 .B dmsetup rename
 .I device_name new_name
 .br
 .B dmsetup rename
-.I device_name --setuuid uuid
-.br
-.B dmsetup message
-.I device_name sector message
-.br
-.B dmsetup ls
-.I [--target target_type] [--exec command] [--tree [-o options]]
+.I device_name
+.B \-\-setuuid
+.I uuid
 .br
-.B dmsetup info 
-.I [device_name]
+.B dmsetup resume
+.I device_name
+.RB [{ \-\-addnodeoncreate | \-\-addnodeonresume }]
+.RS
+.RB [ \-\-readahead
+.RI [ \+ ]< sectors >| auto | none ]
+.RE
 .br
-.B dmsetup info -c|-C|--columns
-.I [--noheadings] [--separator separator] [-o fields] [-O|--sort sort_fields]
-.I [device_name]
+.B dmsetup setgeometry
+.I device_name cyl head sect start
 .br
-.B dmsetup deps
-.I [device_name]
+.B dmsetup splitname
+.I device_name
+.RI [ subsystem ]
 .br
 .B dmsetup status
-.I [--target target_type]
-.I [device_name]
+.RB [ \-\-target
+.IR target_type ]
+.RB [ \-\-noflush ]
+.RI [ device_name ]
 .br
-.B dmsetup table
-.I [--target target_type] [--showkeys]
-.I [device_name]
-.br
-.B dmsetup wait
+.B dmsetup suspend
+.RB [ \-\-nolockfs ]
+.RB [ \-\-noflush ]
 .I device_name
-.I [event_nr]
-.br
-.B dmsetup mknodes
-.I [device_name]
-.br
-.B dmsetup udevcreatecookie
 .br
-.B dmsetup udevreleasecookie
-.I [cookie]
+.B dmsetup table
+.RB [ \-\-target
+.IR target_type ]
+.RB [ \-\-showkeys ]
+.RI [ device_name ]
 .br
-.B dmsetup udevflags
-.I cookie
+.B dmsetup targets
 .br
 .B dmsetup udevcomplete
 .I cookie
 .br
 .B dmsetup udevcomplete_all
+.RI [ age_in_minutes ]
 .br
 .B dmsetup udevcookies
 .br
-.B dmsetup targets
+.B dmsetup udevcreatecookie
 .br
-.B dmsetup version
+.B dmsetup udevflags
+.I cookie
 .br
-.B dmsetup setgeometry
-.I device_name cyl head sect start
+.B dmsetup udevreleasecookie
+.RI [ cookie ]
 .br
-.B dmsetup splitname
+.B dmsetup version
+.br
+.B dmsetup wait
+.RB [ \-\-noflush ]
 .I device_name
-.I [subsystem]
+.RI [ event_nr ]
 .br
 
 .B devmap_name
 .I major minor
 .br
-.B devmap_name 
+.B devmap_name
 .I major:minor
 .ad b
 .SH DESCRIPTION
-dmsetup manages logical devices that use the device-mapper driver.  
+dmsetup manages logical devices that use the device-mapper driver.
 Devices are created by loading a table that specifies a target for
 each sector (512 bytes) in the logical device.
 
-The first argument to dmsetup is a command. 
+The first argument to dmsetup is a command.
 The second argument is the logical device name or uuid.
 
 Invoking the command as \fBdevmap_name\fP is equivalent to
 .br
-\fBdmsetup info -c --noheadings -j \fImajor\fB -m \fIminor\fP.
+\fBdmsetup info \-c \-\-noheadings \-j \fImajor\fB \-m \fIminor\fP.
 .SH OPTIONS
-.IP \fB-c|-C|--columns
-.br
+.TP
+.B \-\-addnodeoncreate
+Ensure /dev/mapper node exists after dmsetup create.
+.TP
+.B \-\-addnodeonresume
+Ensure /dev/mapper node exists after dmsetup resume (default with udev).
+.TP
+.B \-\-checks
+Perform additional checks on the operations requested and report
+potential problems.  Useful when debugging scripts.
+In some cases these checks may slow down operations noticeably.
+.TP
+.BR \-c | \-C | \-\-columns
 Display output in columns rather than as Field: Value lines.
-.IP \fB-h|--help
-.br
+.TP
+.BR \-h | \-\-help
 Outputs a summary of the commands available, optionally including
 the list of report fields (synonym with \fBhelp\fP command).
-.IP \fB--inactive
-.br
-When returning any table information from the kernel report on the 
+.TP
+.B \-\-inactive
+When returning any table information from the kernel report on the
 inactive table instead of the live table.
 Requires kernel driver version 4.16.0 or above.
-.IP \fB-j|--major\ \fImajor
-.br
+.TP
+.IR \fB\-\-manglename \ < mangling_mode >
+Mangle any character not on a whitelist using mangling_mode when
+processing device-mapper device names and UUIDs. The names and UUIDs
+are mangled on input and unmangled on output where the mangling_mode
+is one of: none (no mangling), hex (always do the mangling) and auto
+(only do the mangling if not mangled yet, do nothing if already
+mangled, error on mixed; this is used by default).
+Character whitelist: 0-9, A-Z, a-z, #+-.:=@_. This whitelist is
+also supported by udev. Any character not on a whitelist is replaced
+with its hex value (two digits) prefixed by \\x.
+.TP
+.BR \-j | \-\-major\ \fImajor
 Specify the major number.
-.IP \fB-m|--minor\ \fIminor
-.br
+.TP
+.BR \-m | \-\-minor\ \fIminor
 Specify the minor number.
-.IP \fB-n|--noheadings
-.br
+.TP
+.BR \-n | \-\-noheadings
 Suppress the headings line when using columnar output.
-.IP \fB--noopencount
-.br
+.TP
+.B \-\-noopencount
 Tell the kernel not to supply the open reference count for the device.
-.IP \fB--notable
-.br
+.TP
+.B \-\-notable
 When creating a device, don't load any table.
-.IP \fB--udevcookie\ \fIcookie
-.br
-Use cookie for udev synchronisation.
-.IP \fB--noudevrules
+.TP
+.B \-\-noudevrules
 Do not allow udev to manage nodes for devices in device-mapper directory.
-.br
-.IP \fB--noudevsync
+.TP
+.B \-\-noudevsync
 Do not synchronise with udev when creating, renaming or removing devices.
-.br
-.IP \fB-o|--options
-.br
+.TP
+.BR \-o | \-\-options
 Specify which fields to display.
-.IP \fB-r|--readonly
-.br
-Set the table being loaded read-only.
-.IP \fB--readahead\ [+]<sectors>|auto|none
-.br    
+.TP
+.IR \fB\-\-readahead \ [ \+ ]< sectors >| auto | none
 Specify read ahead size in units of sectors.
-The default value is "auto" which allows the kernel to choose
-a suitable value automatically.  The + prefix lets you
+The default value is \fIauto\fP which allows the kernel to choose
+a suitable value automatically.  The \fI\+\fP prefix lets you
 specify a minimum value which will not be used if it is
 smaller than the value chosen by the kernel.
-"None" is equivalent to specifying zero.
-.IP \fB--table\ <table>
-.br
+The value \fInone\fP is equivalent to specifying zero.
+.TP
+.BR \-r | \-\-readonly
+Set the table being loaded read-only.
+.TP
+.IR \fB\-\-table \ < table >
 Specify a one-line table directly on the command line.
-.IP \fB-u|--uuid
-.br
+.TP
+.B \-\-udevcookie \fIcookie
+Use cookie for udev synchronisation.
+.TP
+.BR \-u | \-\-uuid
 Specify the uuid.
-.IP \fB-y|--yes
-.br
+.TP
+.BR \-y | \-\-yes
 Answer yes to all prompts automatically.
-.IP \fB-v|--verbose\ [-v|--verbose]
-.br
+.TP
+.BR \-v | \-\-verbose \ [ \-v | \-\-verbose ]
 Produce additional output.
-.IP \fB--version
-.br
+.TP
+.B \-\-verifyudev
+If udev synchronisation is enabled, verify that udev operations get performed
+correctly and try to fix up the device nodes afterwards if not.
+.TP
+.B \-\-version
 Display the library and kernel driver version.
+.br
 .SH COMMANDS
-.IP \fBclear
+.TP
+.B clear
 .I device_name
 .br
 Destroys the table in the inactive table slot for device_name.
-.IP \fBcreate
-.I device_name [-u uuid] [--notable | --table <table> | table_file]
+.br
+.TP
+.B create
+.I device_name
+.RB [ \-u
+.IR uuid ]
+.RB [ \-\-notable | \-\-table
+.RI < \fItable >| table_file ]
+.RB [{ \-\-addnodeoncreate | \-\-addnodeonresume }]
+.RB [ \-\-readahead
+.RI [ + ]< sectors >| auto | none ]
 .br
 Creates a device with the given name.
 If table_file or <table> is supplied, the table is loaded and made live.
-Otherwise a table is read from standard input unless --notable is used.
+Otherwise a table is read from standard input unless \-\-notable is used.
 The optional uuid can be used in place of
-device_name in subsequent dmsetup commands.  
+device_name in subsequent dmsetup commands.
 If successful a device will appear as
-/dev/device-mapper/<device-name>.  
+/dev/mapper/<device-name>.
 See below for information on the table format.
-.IP \fBdeps
-.I [device_name]
 .br
-Outputs a list of (major, minor) pairs for devices referenced by the
-live table for the specified device.
-.IP \fBhelp
-.I [-c|-C|--columns]
-.br
-Outputs a summary of the commands available, optionally including
-the list of report fields.
-.IP \fBinfo
-.I [device_name]
-.br
-Outputs some brief information about the device in the form:
-.br
-    State: SUSPENDED|ACTIVE, READ-ONLY
+.TP
+.B deps
+.RB [ \-o
+.IR options ]
+.RI [ device_name ]
 .br
-    Tables present: LIVE and/or INACTIVE
+Outputs a list of devices referenced by the live table for the specified
+device. Device names on output can be customised by following options:
+devno (major and minor pair, used by default), blkdevname (block device name),
+devname (map name for device-mapper devices, equal to blkdevname otherwise).
 .br
-    Open reference count
+.TP
+.B help
+.RB [ \-c | \-C | \-\-columns ]
 .br
-    Last event sequence number (used by \fBwait\fP)
+Outputs a summary of the commands available, optionally including
+the list of report fields.
 .br
-    Major and minor device number
+.TP
+.B info
+.RI [ device_name ]
 .br
-    Number of targets in the live table
+Outputs some brief information about the device in the form:
+.RS
+.RS
+ State: SUSPENDED|ACTIVE, READ-ONLY
+ Tables present: LIVE and/or INACTIVE
+ Open reference count
+ Last event sequence number (used by \fBwait\fP)
+ Major and minor device number
+ Number of targets in the live table
+ UUID
+.RE
+.RE
 .br
-    UUID
-.IP \fBinfo
-.I -c|-C|--columns
-.I [--noheadings] [--separator separator] [-o fields] [-O|--sort sort_fields]
-.I [device_name]
+.TP
+.B info
+.BR \-c | \-C | \-\-columns
+.RB [ \-\-noheadings ]
+.RB [ \-\-separator
+.IR separator ]
+.RB [ \-o
+.IR fields ]
+.RB [ \-O | \-\-sort
+.IR sort_fields ]
+.RI [ device_name ]
 .br
 Output you can customise.
 Fields are comma-separated and chosen from the following list:
@@ -233,206 +340,342 @@ Attributes are: (L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.
 Precede the list with '+' to append
 to the default selection of columns instead of replacing it.
 Precede any sort_field with - for a reverse sort on that column.
-.IP \fBls
-.I [--target target_type]
-.I [--exec command]
-.I [--tree [-o options]]
+.br
+.TP
+.B ls
+.RB [ \-\-target
+.IR target_type ]
+.RB [ \-\-exec
+.IR command ]
+.RB [ \-\-tree ]
+.RB [ \-o
+.IR options ]
 .br
 List device names.  Optionally only list devices that have at least
 one target of the specified type.  Optionally execute a command for
 each device.  The device name is appended to the supplied command.
+Device names on output can be customised by following options: devno (major
+and minor pair, used by default), blkdevname (block device name),
+devname (map name for device-mapper devices, equal to blkdevname otherwise).
 --tree displays dependencies between devices as a tree.
 It accepts a comma-separate list of options.
 Some specify the information displayed against each node:
-device/nodevice; active, open, rw, uuid.
+device/nodevice; blkdevname; active, open, rw, uuid.
 Others specify how the tree is displayed:
 ascii, utf, vt100; compact, inverted, notrunc.
-.IP \fBload|reload
-.I device_name [--table <table> | table_file]
+.br
+.HP
+.BR load | reload
+.I device_name
+.RB [ \-\-table
+.RI < table >| table_file ]
 .br
 Loads <table> or table_file into the inactive table slot for device_name.
 If neither is supplied, reads a table from standard input.
-.IP \fBmessage
+.br
+.HP
+.B wipe_table
+.I device_name
+.br
+Wait for any I/O in-flight through the device to complete, then
+replace the table with a new table that fails any new I/O
+sent to the device.  If successful, this should release any devices 
+held open by the device's table(s).
+.br
+.HP
+.B message
 .I device_name sector message
 .br
 Send message to target. If sector not needed use 0.
-.IP \fBmknodes
-.I [device_name]
+.br
+.HP
+.B mknodes
+.RI [ device_name ]
 .br
 Ensure that the node in /dev/mapper for device_name is correct.
-If no device_name is supplied, ensure that all nodes in /dev/mapper 
+If no device_name is supplied, ensure that all nodes in /dev/mapper
 correspond to mapped devices currently loaded by the device-mapper kernel
 driver, adding, changing or removing nodes as necessary.
-.IP \fBremove
-.I [-f|--force] device_name
+.br
+.HP
+.B mangle
+.RI [ device_name ]
+.br
+Ensure existing device-mapper device name and UUID is in the correct mangled
+form containing only whitelisted characters (supported by udev) and do
+a rename if necessary. Any character not on the whitelist will be mangled
+based on the --manglename setting. Automatic rename works only for device
+names and not for device UUIDs because the kernel does not allow changing
+the UUID of active devices. Any incorrect UUIDs are reported only and they
+must be manually corrected by deactivating the device first and then
+reactivating it with proper mangling mode used (see also --manglename).
+.br
+.HP
+.B remove
+.RB [ \-f | \-\-force ]
+.RB [ \-\-retry ]
+.I device_name
 .br
 Removes a device.  It will no longer be visible to dmsetup.
 Open devices cannot be removed except with older kernels
 that contain a version of device-mapper prior to 4.8.0.
-In this case the device will be deleted when its open_count 
+In this case the device will be deleted when its open_count
 drops to zero.  From version 4.8.0 onwards, if a device can't
 be removed because an uninterruptible process is waiting for
-I/O to return from it, adding --force will replace the table 
-with one that fails all I/O, which might allow the 
-process to be killed.
-.IP \fBremove_all
-.I [-f|--force]
+I/O to return from it, adding \-\-force will replace the table
+with one that fails all I/O, which might allow the
+process to be killed. If an attempt to remove a device fails,
+perhaps because a process run from a quick udev rule
+temporarily opened the device, the \-\-retry option will cause
+the operation to be retried for a few seconds before failing.
+.br
+.HP
+.B remove_all
+.RB [ \-f | \-\-force ]
 .br
 Attempts to remove all device definitions i.e. reset the driver.
 Use with care!  From version 4.8.0 onwards, if devices can't
 be removed because uninterruptible processes are waiting for
-I/O to return from them, adding --force will replace the table 
-with one that fails all I/O, which might allow the 
+I/O to return from them, adding \-\-force will replace the table
+with one that fails all I/O, which might allow the
 process to be killed.  This also runs \fBmknodes\fP afterwards.
-.IP \fBrename
+.br
+.HP
+.B rename
 .I device_name new_name
 .br
 Renames a device.
-.IP \fBrename
-.I device_name --setuuid uuid
+.br
+.HP
+.B rename
+.I device_name
+.B \-\-setuuid
+.I uuid
 .br
 Sets the uuid of a device that was created without a uuid.
 After a uuid has been set it cannot be changed.
-.IP \fBresume
+.br
+.TP
+.B resume
 .I device_name
+.RB [{ \-\-addnodeoncreate | \-\-addnodeonresume }]
+.RB [ \-\-readahead
+.RI [ + ]< sectors >| auto | none ]
 .br
-Un-suspends a device.  
+Un-suspends a device.
 If an inactive table has been loaded, it becomes live.
 Postponed I/O then gets re-queued for processing.
-.IP \fBsetgeometry
-.I device_name cyl head sect start
+.br
+.TP
+.B setgeometry \fIdevice_name cyl head sect start
 .br
 Sets the device geometry to C/H/S.
-.IP \fBsplitname
+.br
+.HP
+.B splitname
 .I device_name
-.I [subsystem]
+.RI [ subsystem ]
 .br
 Splits given device name into subsystem constituents.
 Default subsystem is LVM.
-.IP \fBstatus
-.I [--target target_type]
-.I [device_name]
+.br
+.TP
+.B status
+.RB [ \-\-target
+.IR target_type ]
+.RB [ \-\-noflush ]
+.RI [ device_name ]
 .br
 Outputs status information for each of the device's targets.
-With --target, only information relating to the specified target type
-is displayed.
-.IP \fBsuspend
-.I [--nolockfs] [--noflush]
+With \-\-target, only information relating to the specified target type
+any is displayed.  With \-\-noflush, the thin target (from version 1.3.0)
+doesn't commit any outstanding changes to disk before reporting its statistics.
+.br
+.HP
+.B suspend
+.RB [ \-\-nolockfs ]
+.RB [ \-\-noflush ]
 .I device_name
 .br
 Suspends a device.  Any I/O that has already been mapped by the device
 but has not yet completed will be flushed.  Any further I/O to that
 device will be postponed for as long as the device is suspended.
-If there's a filesystem on the device which supports the operation, 
-an attempt will be made to sync it first unless --nolockfs is specified.
+If there's a filesystem on the device which supports the operation,
+an attempt will be made to sync it first unless \-\-nolockfs is specified.
 Some targets such as recent (October 2006) versions of multipath may support
-the --noflush option.  This lets outstanding I/O that has not yet reached the
+the \-\-noflush option.  This lets outstanding I/O that has not yet reached the
 device to remain unflushed.
-.IP \fBtable
-.I [--target target_type] [--showkeys]
-.I [device_name]
+.br
+.TP
+.B table
+.RB [ \-\-target
+.IR target_type ]
+.RB [ \-\-showkeys ]
+.RI [ device_name ]
 .br
 Outputs the current table for the device in a format that can be fed
 back in using the create or load commands.
-With --target, only information relating to the specified target type
+With \-\-target, only information relating to the specified target type
 is displayed.
 Encryption keys are suppressed in the table output for the crypt
-target unless the --showkeys parameter is supplied.
-.IP \fBtargets
+target unless the \-\-showkeys parameter is supplied.
+.br
+.TP
+.B targets
 .br
 Displays the names and versions of the currently-loaded targets.
 .br
-.IP \fBudevcreatecookie
+.HP
+.B udevcomplete
+.I cookie
+.br
+Wake any processes that are waiting for udev to complete processing the specified cookie.
+.br
+.HP
+.B udevcomplete_all
+.RI [ age_in_minutes ]
+.br
+Remove all cookies older than the specified number of minutes.
+Any process waiting on a cookie will be resumed immediately.
+.br
+.HP
+.B udevcookies
+.br
+List all existing cookies. Cookies are system-wide semaphores with keys
+prefixed by two predefined bytes (0x0D4D).
+.br
+.TP
+.B udevcreatecookie
 .br
 Creates a new cookie to synchronize actions with udev processing.
 The output is a cookie value. Normally we don't need to create cookies since
 dmsetup creates and destroys them for each action automatically. However, we can
 generate one explicitly to group several actions together and use only one
 cookie instead. We can define a cookie to use for each relevant command by using
---udevcookie option. Alternatively, we can export this value into the environment
+\-\-udevcookie option. Alternatively, we can export this value into the environment
 of the dmsetup process as DM_UDEV_COOKIE variable and it will be used automatically
 with all subsequent commands until it is unset.
 Invoking this command will create system-wide semaphore that needs to be cleaned
 up explicitly by calling udevreleasecookie command.
 .br
-.IP \fBudevreleasecookie
-.I [cookie]
-.br
-Waits for all pending udev processing bound to given cookie value and clean up
-the cookie with underlying semaphore. If the cookie is not given directly,
-the command will try to use a value defined by DM_UDEV_COOKIE environment variable.
-.br
-.IP \fBudevflags
+.HP
+.B udevflags
 .I cookie
 .br
 Parses given cookie value and extracts any udev control flags encoded.
 The output is in environment key format that is suitable for use in udev
-rules. If the flag has its symbolic name assigned then the ouput is
+rules. If the flag has its symbolic name assigned then the output is
 DM_UDEV_FLAG_<flag_name>='1', DM_UDEV_FLAG<flag_position>='1' otherwise.
 Subsystem udev flags don't have symbolic names assigned and these ones are
 always reported as DM_SUBSYSTEM_UDEV_FLAG<flag_position>='1'. There are
 16 udev flags altogether.
 .br
-.IP \fBudevcomplete
-.I cookie
-.br
-Wake any processes that are waiting for udev to complete processing the specified cookie.
+.HP
+.B udevreleasecookie
+.RI [ cookie ]
 .br
-.IP \fBudevcomplete_all
-Remove all cookies. Any process waiting on a cookie will be resumed immediately.
-.br
-.IP \fBudevcookies
-List all existing cookies. Cookies are system-wide semaphores with keys
-prefixed by two predefined bytes (0x0D4D).
+Waits for all pending udev processing bound to given cookie value and clean up
+the cookie with underlying semaphore. If the cookie is not given directly,
+the command will try to use a value defined by DM_UDEV_COOKIE environment variable.
 .br
-.IP \fBversion
+.TP
+.B version
 .br
 Outputs version information.
-.IP \fBwait
+
+.TP
+.B wait
+.RB [ \-\-noflush ]
 .I device_name
-.I [event_nr]
+.RI [ event_nr ]
 .br
 Sleeps until the event counter for device_name exceeds event_nr.
-Use -v to see the event number returned.
+Use \-v to see the event number returned.
 To wait until the next event is triggered, use \fBinfo\fP to find
-the last event number.  
+the last event number.
+With \-\-noflush, the thin target (from version 1.3.0) doesn't commit
+any outstanding changes to disk before reporting its statistics.
 .SH TABLE FORMAT
 Each line of the table specifies a single target and is of the form:
-.br
-    logical_start_sector num_sectors target_type target_args
-.br
-.br
-
-There are currently three simple target types available together 
-with more complex optional ones that implement snapshots and mirrors.
-
-.IP \fBlinear
+.P
+.I logical_start_sector num_sectors
+.B target_type
+.RI < target_args >
+.P
+Simple target types and <target_args> include: 
+.HP
+.B linear
 .I destination_device start_sector
 .br
 The traditional linear mapping.
-
-.IP \fBstriped
-.I num_stripes chunk_size [destination start_sector]+
+.HP
+.B striped
+.I num_stripes chunk_size
+.RI [ destination
+.IR start_sector ]+
 .br
 Creates a striped area.
 .br
 e.g. striped 2 32 /dev/hda1 0 /dev/hdb1 0
 will map the first chunk (16k) as follows:
+.RS
+.RS
+ LV chunk 1 -> hda1, chunk 1
+ LV chunk 2 -> hdb1, chunk 1
+ LV chunk 3 -> hda1, chunk 2
+ LV chunk 4 -> hdb1, chunk 2
+ etc.
+.RE
+.RE
+.TP
+.B error
 .br
-    LV chunk 1 -> hda1, chunk 1
+Errors any I/O that goes to this area.  Useful for testing or
+for creating devices with holes in them.
+.TP
+.B zero
 .br
-    LV chunk 2 -> hdb1, chunk 1
+Returns blocks of zeroes on reads.  Any data written is discarded silently.
+This is a block-device equivalent of the /dev/zero character-device data sink
+described in \fBnull(4)\fP.
+.P
+More complex targets include:
+.TP
+.B crypt
+.br
+Transparent encryption of block devices using the kernel crypto API.
+.TP
+.B delay
 .br
-    LV chunk 3 -> hda1, chunk 2
+Delays reads and/or writes to different devices.  Useful for testing.
+.TP
+.B flakey
 .br
-    LV chunk 4 -> hdb1, chunk 2
+Creates a similar mapping to the linear target but
+exhibits unreliable behaviour periodically.
+Useful for simulating failing devices when testing.
+.TP
+.B mirror
 .br
-    etc.
-
-.IP \fBerror
+Mirrors data across two or more devices.
+.HP
+.B multipath
 .br
-Errors any I/O that goes to this area.  Useful for testing or
-for creating devices with holes in them.
+Mediates access through multiple paths to the same device.
+.TP
+.BR raid
+.br
+Offers an interface to the kernel's software raid driver, md.
+.HP
+.B snapshot
+.br
+Supports snapshots of devices.
+.P
+To find out more about the various targets and their table formats and status
+lines, please read the files in the Documentation/device-mapper directory in
+the kernel source tree.  
+(Your distribution might include a copy of this information in the 
+documentation directory for the device-mapper package.)
 
 .SH EXAMPLES
 
@@ -444,7 +687,7 @@ for creating devices with holes in them.
 1028160 3903762 linear /dev/hdb 0
 
 
-# A table to stripe across the two disks, 
+# A table to stripe across the two disks,
 .br
 # and add the spare space from
 .br
@@ -456,13 +699,13 @@ for creating devices with holes in them.
 
 .SH ENVIRONMENT VARIABLES
 .TP
-\fBDM_DEV_DIR\fP
+.B DM_DEV_DIR
 The device directory name.
 Defaults to "/dev" and must be an absolute path.
 .TP
-\fBDM_UDEV_COOKIE\fP
+.B DM_UDEV_COOKIE
 A cookie to use for all relevant commands to synchronize with udev processing.
-It is an alternative to using --udevcookie option.
+It is an alternative to using \-\-udevcookie option.
 
 .SH AUTHORS
 Original version: Joe Thornber (thornber@sistina.com)
index eeec2d32f1846fe6f281889a556dcb4cc15ba681..46be1ff22ea2dd92a608a238302416c99823e140 100644 (file)
@@ -1,64 +1,77 @@
 .TH "FSADM" "8" "LVM TOOLS #VERSION#" "Red Hat, Inc" "\""
 .SH "NAME"
 fsadm \- utility to resize or check filesystem on a device
-.SH "SYNOPSIS"
+.SH SYNOPSIS
 .B fsadm
-.RI [options]\ check\ device
-
+.RI [ options ]
+.B check
+.I device
+.sp
 .B fsadm
-.RI [options]\ resize\ device\ [new_size[BKMGTEP]]
-
-.SH "DESCRIPTION"
-\fBfsadm\fR utility resizes or checks the filesystem on a device.
-It tries to use the same API for \fBext2/ext3/ext4\fR,
-\fBReiserFS\fR and \fBXFS\fR filesystem.
-.SH "OPTIONS"
+.RI [ options ]
+.B resize
+.I device
+.RI [ new_size [ BKMGTEP ]]
+.sp
+.SH DESCRIPTION
+fsadm utility checks or resizes the filesystem on a device.
+It tries to use the same API for 
+.IR ext2 ", " ext3 ", " ext4 ", " ReiserFS " and " XFS
+filesystem.
+.SH OPTIONS
 .TP
-\fB\-h \-\-help\fR
-\(em print help message
+.BR \-e ", " \-\-ext\-offline
+Unmount ext2/ext3/ext4 filesystem before doing resize.
 .TP
-\fB\-v \-\-verbose\fR
-\(em be more verbose
+.BR \-f ", " \-\-force
+Bypass some sanity checks.
 .TP
-\fB\-e \-\-ext\-offline\fR
-\(em unmount ext2/ext3/ext4 filesystem before doing resize
+.BR \-h ", " \-\-help
+Display the help text.
 .TP
-\fB\-f \-\-force\fR
-\(em bypass some sanity checks
+.BR \-n ", " \-\-dry\-run
+Print commands without running them.
 .TP
-\fB\-n \-\-dry\-run\fR
-\(em print commands without running them
+.BR \-v ", " \-\-verbose
+Be more verbose.
 .TP
-\fB\-y \-\-yes\fR
-\(em answer "yes" at any prompts
+.BR \-y ", " \-\-yes
+Answer "yes" at any prompts.
 .TP
-\fBnew_size\fR
-\(em Absolute number of filesystem blocks to be in the filesystem,
+.I new_size
+Absolute number of filesystem blocks to be in the filesystem,
 or an absolute size using a suffix (in powers of 1024).
 If new_size is not supplied, the whole device is used.
 
-.SH "DIAGNOSTICS"
+.SH DIAGNOSTICS
 On successful completion, the status code is 0.
 A status code of 2 indicates the operation was interrupted by the user.
 A status code of 3 indicates the requested check operation could not be performed
-because the filesystem is mounted and does not support an online fsck.
+because the filesystem is mounted and does not support an online 
+.BR fsck (8).
 A status code of 1 is used for other failures.
 
-.SH "EXAMPLES"
-"fsadm \-e \-y resize /dev/vg/test 1000M" tries to resize the filesystem
-on logical volume /dev/vg/test. If /dev/vg/test contains ext2/ext3/ext4
+.SH EXAMPLES
+Resize the filesystem on logical volume /dev/vg/test to 1000 megabytes.
+If /dev/vg/test contains ext2/ext3/ext4
 filesystem it will be unmounted prior the resize.
 All [y|n] questions will be answered 'y'.
-.SH "ENVIRONMENT VARIABLES"
+.sp
+.B fsadm \-e \-y resize /dev/vg/test 1000M
+.SH ENVIRONMENT VARIABLES
 .TP
-\fBTMPDIR\fP
-Where the temporary directory should be created.
+.B TMPDIR
+The temporary directory name for mount points. Defaults to "/tmp". 
 .TP
-.BR
-.SH "SEE ALSO"
+.B DM_DEV_DIR
+The device directory name.
+Defaults to "/dev" and must be an absolute path.
+
+.SH SEE ALSO
 .BR lvm (8),
 .BR lvresize (8),
 .BR lvm.conf (5),
+.BR fsck (8),
 .BR tune2fs (8),
 .BR resize2fs (8),
 .BR reiserfstune (8),
index e269802970469c7e82d0cab96e0dfce7168e7a66..32a05800b3cc66eb20e3cab24304a289aaee02bc 100644 (file)
@@ -3,49 +3,84 @@
 lvchange \- change attributes of a logical volume
 .SH SYNOPSIS
 .B lvchange
-[\-\-addtag Tag]
-[\-A|\-\-autobackup y|n] [\-a|\-\-available y|n|ey|en|ly|ln]
-[\-\-alloc AllocationPolicy]
-[\-C|\-\-contiguous y|n] [\-d|\-\-debug] [\-\-deltag Tag]
-[\-\-resync]
-[\-h|\-?|\-\-help]
-[\-\-ignorelockingfailure]
-[\-\-ignoremonitoring]
-[\-\-monitor {y|n}]
-[\-\-poll {y|n}]
-[\-\-sysinit]
-[\-\-noudevsync]
-[\-M|\-\-persistent y|n] [\-\-minor minor]
-[\-P|\-\-partial]
-[\-p|\-\-permission r|rw] [\-r/\-\-readahead ReadAheadSectors|auto|none]
-[\-\-refresh]
-[\-t|\-\-test]
-[\-v|\-\-verbose] LogicalVolumePath [LogicalVolumePath...]
+.RB [ \-\-addtag
+.IR Tag ]
+.RB [ \-A | \-\-autobackup
+.RI { y | n }]
+.RB [ \-a | \-\-activate
+.RI [ a | e | l ]{ y | n }]
+.RB [ \-\-alloc
+.IR AllocationPolicy ]
+.RB [ \-C | \-\-contiguous
+.RI { y | n }]
+.RB [ \-d | \-\-debug ]
+.RB [ \-\-deltag
+.IR Tag ]
+.RB [ \-\-discards
+.RI { ignore | nopassdown | passdown }]
+.RB [ \-\-resync ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-\-ignorelockingfailure ]
+.RB [ \-\-ignoremonitoring ]
+.RB [ \-\-monitor
+.RI { y | n }]
+.RB [ \-\-poll
+.RI { y | n }]
+.RB [ \-\-sysinit ]
+.RB [ \-\-noudevsync ]
+.RB [ \-M | \-\-persistent
+.RI { y | n }]
+.RB [ \-\-minor
+.IR minor ]
+.RB [ \-P | \-\-partial ]
+.RB [ \-p | \-\-permission
+.RI { r | rw }]
+.RB [ \-r | \-\-readahead
+.RI { ReadAheadSectors | auto | none }]
+.RB [ \-\-refresh ]
+.RB [ \-t | \-\-test ]
+.RB [ \-v | \-\-verbose ]
+.RB [ \-Z | \-\-zero
+.RI { y | n }]
+.I LogicalVolumePath
+.RI [ LogicalVolumePath ...]
 .SH DESCRIPTION
 lvchange allows you to change the attributes of a logical volume
 including making them known to the kernel ready for use.
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .TP
-.I \-a, \-\-available y|n|ey|en|ly|ln
+.BR \-a ", " \-\-activate " [" \fIa | \fIe | \fIl ]{ \fIy | \fIn }
 Controls the availability of the logical volumes for use.
 Communicates with the kernel device-mapper driver via
-libdevmapper to activate (-ay) or deactivate (-an) the 
-logical volumes.
+libdevmapper to activate (\-ay) or deactivate (\-an) the
+logical volumes. If autoactivation option is used (\-aay),
+the logical volume is activated only if it matches an item in
+the activation/auto_activation_volume_list set in lvm.conf.
+Autoactivation is not yet supported for logical volumes that
+are part of partial or clustered volume groups.
 .IP
 If clustered locking is enabled, -aey will activate exclusively
 on one node and -aly will activate only on the local node.
 To deactivate only on the local node use -aln.
-Logical volumes with single-host snapshots are always activated 
+Logical volumes with single-host snapshots are always activated
 exclusively because they can only be used on one node at once.
 .TP
-.I \-C, \-\-contiguous y|n
+.BR \-C ", " \-\-contiguous " {" \fIy | \fIn }
 Tries to set or reset the contiguous allocation policy for
 logical volumes. It's only possible to change a non-contiguous
 logical volume's allocation policy to contiguous, if all of the
 allocated physical extents are already contiguous.
 .TP
-.I \-\-resync
+.BR \-\-discards " {" \fIignore | \fInopassdown | \fIpassdown }
+Set this to \fIignore\fP to ignore any discards received by a
+thin pool Logical Volume.  Set to \fInopassdown\fP to process such
+discards within the thin pool itself and allow the no-longer-needed
+extents to be overwritten by new data.  Set to \fIpassdown\fP (the
+default) to process them both within the thin pool itself and to 
+pass them down the underlying device.
+.TP
+.B \-\-resync
 Forces the complete resynchronization of a mirror.  In normal
 circumstances you should not need this option because synchronization
 happens automatically.  Data is read from the primary mirror device
@@ -53,53 +88,60 @@ and copied to the others, so this can take a considerable amount of
 time - and during this time you are without a complete redundant copy
 of your data.
 .TP
-.I \-\-minor minor
+.B \-\-minor \fIminor
 Set the minor number.
 .TP
-.I \-\-monitor y|n
+.BR \-\-monitor " {" \fIy | \fIn }
 Start or stop monitoring a mirrored or snapshot logical volume with
 dmeventd, if it is installed.
 If a device used by a monitored mirror reports an I/O error,
-the failure is handled according to 
+the failure is handled according to
 \fBmirror_image_fault_policy\fP and \fBmirror_log_fault_policy\fP
 set in \fBlvm.conf\fP.
 .TP
-.I \-\-poll y|n
+.BR \-\-poll " {" \fIy | \fIn }
 Without polling a logical volume's backgrounded transformation process
 will never complete.  If there is an incomplete pvmove or lvconvert (for
-example, on rebooting after a crash), use \fB--poll y\fP to restart the
+example, on rebooting after a crash), use \fB\-\-poll y\fP to restart the
 process from its last checkpoint.  However, it may not be appropriate to
-immediately poll a logical volume when it is activated, use \fB--poll
-n\fP to defer and then \fB--poll y\fP to restart the process.
+immediately poll a logical volume when it is activated, use
+\fB\-\-poll n\fP to defer and then \fB\-\-poll y\fP to restart the process.
 .TP
-.I \-\-sysinit
-Indicates that lvchange(8) is being invoked from early system initialisation
-scripts (e.g. rc.sysinit or an initrd), before writeable filesystems are
-available. As such, some functionality needs to be disabled and this option
+.B \-\-sysinit
+Indicates that \fBlvchange\fP(8) is being invoked from early system
+initialisation scripts (e.g. rc.sysinit or an initrd),
+before writeable filesystems are available. As such,
+some functionality needs to be disabled and this option
 acts as a shortcut which selects an appropriate set of options. Currently
-this is equivalent to using  \fB--ignorelockingfailure\fP, \fB--ignoremonitoring\fP,
-\fB--poll n\fP and setting \fBLVM_SUPPRESS_LOCKING_FAILURE_MESSAGES\fP
+this is equivalent to using  \fB\-\-ignorelockingfailure\fP,
+\fB\-\-ignoremonitoring\fP, \fB\-\-poll n\fP and setting
+\fBLVM_SUPPRESS_LOCKING_FAILURE_MESSAGES\fP
 environment variable.
+
+If \fB\-\-sysinit\fP is used in conjunction with lvmetad(8) enabled and running,
+autoactivation is preferred over manual activation via direct lvchange call.
+Logical volumes are autoactivated according to auto_activation_volume_list
+set in lvm.conf(5).
 .TP
-.I \-\-noudevsync
+.B \-\-noudevsync
 Disable udev synchronisation. The
 process will not wait for notification from udev.
 It will continue irrespective of any possible udev processing
 in the background.  You should only use this if udev is not running
 or has rules that ignore the devices LVM2 creates.
 .TP
-.I \-\-ignoremonitoring
-Make no attempt to interact with dmeventd unless \-\-monitor
+.B \-\-ignoremonitoring
+Make no attempt to interact with dmeventd unless \fB\-\-monitor\fP
 is specified.
 Do not use this if dmeventd is already monitoring a device.
 .TP
-.I \-M, \-\-persistent y|n
+.BR \-M ", " \-\-persistent " {" \fIy | \fIn }
 Set to y to make the minor number specified persistent.
 .TP
-.I \-p, \-\-permission r|rw
+.BR \-p ", " \-\-permission " {" \fIr | \fIrw }
 Change access permission to read-only or read/write.
 .TP
-.I \-r, \-\-readahead ReadAheadSectors|auto|none
+.BR \-r ", " \-\-readahead " {" \fIReadAheadSectors | \fIauto | \fInone }
 Set read ahead sector count of this logical volume.
 For volume groups with metadata in lvm1 format, this must
 be a value between 2 and 120 sectors.
@@ -107,16 +149,21 @@ The default value is "auto" which allows the kernel to choose
 a suitable value automatically.
 "None" is equivalent to specifying zero.
 .TP
-.I \-\-refresh
+.B \-\-refresh
 If the logical volume is active, reload its metadata.
 This is not necessary in normal operation, but may be useful
-if something has gone wrong or if you're doing clustering 
+if something has gone wrong or if you're doing clustering
 manually without a clustered lock manager.
+.TP
+.BR \-Z ", " \-\-zero " {" \fIy | \fIn }
+Set zeroing mode for thin pool. Note: already provisioned blocks from pool
+in non-zero mode are not cleared in unwritten parts when setting zero to
+\fIy\fP.
 .SH Examples
-"lvchange -pr vg00/lvol1" changes the permission on 
-volume lvol1 in volume group vg00 to be read-only.
-
+Changes the permission on volume lvol1 in volume group vg00 to be read-only:
+.sp
+.B lvchange -pr vg00/lvol1
 .SH SEE ALSO
-.BR lvm (8), 
+.BR lvm (8),
 .BR lvcreate (8),
 .BR vgchange (8)
index 8e487931591943200591a5a52862b1bd297598f9..265971942d3cbd15f58b64ff04c49a137212b5af 100644 (file)
@@ -3,57 +3,92 @@
 lvconvert \- convert a logical volume from linear to mirror or snapshot
 .SH SYNOPSIS
 .B lvconvert
-\-m|\-\-mirrors Mirrors [\-\-mirrorlog {disk|core|mirrored}] [\-\-corelog] [\-R|\-\-regionsize MirrorLogRegionSize]
-[\-A|\-\-alloc AllocationPolicy]
-[\-b|\-\-background] [\-f|\-\-force] [\-i|\-\-interval Seconds]
-[\-h|\-?|\-\-help]
-[\-\-stripes Stripes [\-I|\-\-stripesize StripeSize]]
-[\-\-noudevsync]
-[\-v|\-\-verbose] [\-y|\-\-yes]
-[\-\-version]
-.br
-LogicalVolume[Path] [PhysicalVolume[Path][:PE[-PE]]...]
-.br
-
-.br
-.B lvconvert
-\-\-splitmirrors Images \-\-name SplitLogicalVolumeName
-.br
-MirrorLogicalVolume[Path] [SplittablePhysicalVolume[Path][:PE[-PE]]...]
-.br
-
-.br
-.B lvconvert
-\-s|\-\-snapshot [\-c|\-\-chunksize ChunkSize]
-[\-h|\-?|\-\-help]
-[\-\-noudevsync]
-[\-v|\-\-verbose]
-[\-Z|\-\-zero y|n]
-[\-\-version]
-.br
-OriginalLogicalVolume[Path] SnapshotLogicalVolume[Path]
-.br
-
-.br
+.BR \-m | \-\-mirrors
+.I Mirrors
+.RB [ \-\-mirrorlog
+.RI { disk | core | mirrored }]
+.RB [ \-\-corelog ]
+.RB [ \-R | \-\-regionsize
+.IR MirrorLogRegionSize ]
+.RB [ \-\-type
+.IR SegmentType ]
+.RB [ \-A | \-\-alloc
+.IR AllocationPolicy ]
+.RB [ \-b | \-\-background ]
+.RB [ \-f | \-\-force ]
+.RB [ \-i | \-\-interval
+.IR Seconds ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-\-stripes
+.I Stripes
+.RB [ \-I | \-\-stripesize
+.IR StripeSize ]]
+.RB [ \-\-noudevsync ]
+.RB [ \-v | \-\-verbose ]
+.RB [ \-y | \-\-yes ]
+.RB [ \-\-version ]
+.IR LogicalVolume [ Path ]
+.RI [ PhysicalVolume [ Path ][ :PE [ -PE ]]...]
+.sp
+.B lvconvert \-\-splitmirrors \fIImages
+.RB [ \-\-name
+.IR SplitLogicalVolumeName ]
+.RB [ \-\-trackchanges ]
+.IR MirrorLogicalVolume [ Path ]
+.RI [ SplittablePhysicalVolume [ Path ][ :PE [ -PE ]]...]
+.sp
 .B lvconvert
-\-\-merge [\-b|\-\-background] [\-i|\-\-interval Seconds]
-[\-h|\-?|\-\-help]
-[\-v|\-\-verbose]
-[\-\-version]
-SnapshotLogicalVolume[Path]...
-.br
+.BR \-s | \-\-snapshot
+.RB [ \-c | \-\-chunksize
+.IR ChunkSize ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-\-noudevsync ]
+.RB [ \-v | \-\-verbose ]
+.RB [ \-Z | \-\-zero
+.RI { y | n }]
+.RB [ \-\-version ]
+.IR OriginalLogicalVolume [ Path ]
+.IR SnapshotLogicalVolume [ Path ]
+.sp
+.B lvconvert \-\-merge
+.RB [ \-b | \-\-background ]
+.RB [ \-i | \-\-interval
+.IR Seconds ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-v | \-\-verbose ]
+.RB [ \-\-version ]
+.IR LogicalVolume [ Path ]...
+.sp
+.B lvconvert \-\-thinpool
+.IR ThinPoolLogicalVolume { Name | Path }
+.RB [ \-c | \-\-chunksize
+.IR ChunkSize ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-v | \-\-verbose ]
+.RB [ \-\-version ]
+.RB [ \-Z | \-\-zero
+.RI { y | n }]
+.IR ThinMetadataLogicalVolume { Name | Path }
+.sp
+.B lvconvert \-\-repair
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-v | \-\-verbose ]
+.RB [ \-\-version ]
+.IR LogicalVolume [ Path ]
+.RI [ PhysicalVolume [ Path ]...]
+.sp
+.B lvconvert \-\-replace \fIPhysicalVolume
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-v | \-\-verbose ]
+.RB [ \-\-version ]
+.IR LogicalVolume [ Path ]
+.RI [ PhysicalVolume [ Path ]...]
 
-.br
-.B lvconvert
-\-\-repair
-[\-h|\-?|\-\-help]
-[\-v|\-\-verbose]
-[\-\-version]
-LogicalVolume[Path] [PhysicalVolume[Path]...]
 .SH DESCRIPTION
-lvconvert will change a linear logical volume to a mirror
-logical volume or to a snapshot of linear volume and vice versa.
-It is also used to add and remove disk logs from mirror devices.
+lvconvert is used to change the segment type (i.e. linear, mirror, etc) or
+characteristics of a logical volume.  For example, it can add or remove the
+redundant images of a logical volume, change the log type of a mirror, or
+designate a logical volume as a snapshot repository.
 .br
 If the conversion requires allocation of physical extents (for
 example, when converting from linear to mirror) and you specify
@@ -64,19 +99,19 @@ these physical extents.  If the conversion frees physical extents
 mirror legs) and you specify one or more PhysicalVolumes,
 the freed extents come first from the specified PhysicalVolumes.
 .SH OPTIONS
-See \fBlvm\fP for common options.
-.br
-Exactly one of \-\-splitmirrors, \-\-mirrors, \-\-repair, \-\-snapshot
-or \-\-merge arguments is required.
+See \fBlvm\fP(8) for common options.
 .br
+Exactly one of 
+.BR \-\-splitmirrors ", " \-\-mirrors ", " \-\-repair ", " \-\-snapshot
+or \fB\-\-merge\fP arguments is required.
 .TP
-.I \-m, \-\-mirrors Mirrors
+.BR \-m ", " \-\-mirrors " " \fIMirrors
 Specifies the degree of the mirror you wish to create.
-For example, "-m 1" would convert the original logical
+For example, "\fB-m 1\fP" would convert the original logical
 volume to a mirror volume with 2-sides; that is, a
 linear volume plus one copy.
 .TP
-.I \-\-mirrorlog {disk|core|mirrored}
+.IR \fB\-\-mirrorlog " {" disk | core | mirrored }
 Specifies the type of log to use.
 The default is disk, which is persistent and requires
 a small amount of storage space, usually on a separate device
@@ -86,58 +121,69 @@ regenerated by copying the data from the first device again every
 time the device is activated - perhaps, for example, after every reboot.
 Using "mirrored" will create a persistent log that is itself mirrored.
 .TP
-.I \-\-corelog
-The optional argument "--corelog" is the same as specifying "--mirrorlog core".
+.B \-\-corelog
+The optional argument \fB--corelog\fP is the same as specifying
+\fB--mirrorlog core\fP.
 .TP
-.I \-R, \-\-regionsize MirrorLogRegionSize
+.BR \-R ", " \-\-regionsize " " \fIMirrorLogRegionSize
 A mirror is divided into regions of this size (in MB), and the mirror log
 uses this granularity to track which regions are in sync.
 .TP
-.I \-b, \-\-background
+.B \-\-type \fISegmentType
+Used to convert a logical volume to another segment type or to explicitly state
+the desired RAID1 segment type (\fImirror\fP or \fIraid1\fP) when converting
+a linear logical volume to a mirror with the \fB-m\fP argument.
+.TP
+.BR \-b ", " \-\-background
 Run the daemon in the background.
 .TP
-.I \-i, \-\-interval Seconds
+.BR \-i ", " \-\-interval " " \fISeconds
 Report progress as a percentage at regular intervals.
-.br
 .TP
-.I \-\-noudevsync
+.B \-\-noudevsync
 Disable udev synchronisation. The
 process will not wait for notification from udev.
 It will continue irrespective of any possible udev processing
 in the background.  You should only use this if udev is not running
 or has rules that ignore the devices LVM2 creates.
-.br
-
-
 .TP
-.I \-\-splitmirrors Images
+.B \-\-splitmirrors \fIImages
 The number of redundant Images of a mirror to be split off and used
 to form a new logical volume.  A name must be supplied for the
-newly-split-off logical volume using the \-\-name argument.
-
+newly-split-off logical volume using the \fB\-\-name\fP argument, unless
+the \fB\-\-trackchanges\fP argument is given.
 .TP
-.I \-n Name
+.B \-n \fIName
 The name to apply to a logical volume which has been split off from
 a mirror logical volume.
-.br
-
+.TP
+.B \-\-trackchanges
+Used with \fB\-\-splitmirrors\fP on a raid1 device, this tracks changes so
+that the read-only detached image can be merged efficiently back into
+the mirror later. Only the regions of the detatched device where
+the data changed get resynchronized.
 
+Please note that this feature is only supported with the new md-based mirror
+implementation and not with the original device-mapper mirror implementation.
 .TP
-.I \-s, \-\-snapshot
+.B \-s, \-\-snapshot
 Create a snapshot from existing logical volume using another
 existing logical volume as its origin.
 .TP
-.I \-c, \-\-chunksize ChunkSize
-Power of 2 chunk size for the snapshot logical volume between 4k and 512k.
+.BR \-c ", " \-\-chunksize " " \fIChunkSize
+Power of 2 chunk size for the snapshot logical volume between 4KiB and 512KiB.
 .TP
-.I \-Z, \-\-zero y|n
+.BR \-Z ", " \-\-zero " {" \fIy | \fIn }
 Controls zeroing of the first KB of data in the snapshot.
 If the volume is read-only the snapshot will not be zeroed.
 .TP
-.I \-\-merge
-Merges a snapshot into its origin volume.  To check if your kernel
-supports this feature, look for 'snapshot-merge' in the output
-of 'dmsetup targets'.  If both the origin and snapshot volume are not
+.B \-\-merge
+Merges a snapshot into its origin volume or merges a raid1 image that has
+been split from its mirror with \fB\-\-trackchanges\fP back into its mirror.
+
+To check if your kernel supports the snapshot merge feature, look
+for 'snapshot-merge' in the output
+of \fBdmsetup targets\fP.  If both the origin and snapshot volume are not
 open the merge will start immediately.  Otherwise, the merge will start
 the first time either the origin or snapshot are activated and both are closed.
 Merging a snapshot into an origin that cannot be closed, for example a root
@@ -148,70 +194,107 @@ origin appear as they were directed to the snapshot being merged.  When the
 merge finishes, the merged snapshot is removed.  Multiple snapshots may
 be specified on the commandline or a @tag may be used to specify
 multiple snapshots be merged to their respective origin.
-.br
-
-
 .TP
-.I \-\-repair
+.B \-\-repair
 Repair a mirror after suffering a disk failure. The mirror will be brought back
 into a consistent state.  By default, the original number of mirrors will be
-restored if possible.  Specify \-y on the command line to skip the prompts.
-Use \-f if you do not want any replacement.  Additionally, you may use
-\-\-use-policies to use the device replacement policy specified in lvm.conf,
+restored if possible.  Specify \fB\-y\fP on the command line to skip
+the prompts. Use \fB\-f\fP if you do not want any replacement.
+Additionally, you may use \fB\-\-use-policies\fP to use the device
+replacement policy specified in \fBlvm.conf\fP(5),
 viz. activation/mirror_log_fault_policy or
 activation/mirror_device_fault_policy.
-.br
+.TP
+.B \-\-replace \fIPhysicalVolume
+Remove the specified device (\fIPhysicalVolume\fP) and replace it with one
+that is available in the volume group or from the specific list provided.
+This option is only available to RAID segment types
+(e.g. "raid1", "raid5", etc).
+
 .SH Examples
-"lvconvert -m1 vg00/lvol1"
-.br
-converts the linear logical volume "vg00/lvol1" to
-a two-way mirror logical volume.
+Converts the linear logical volume "vg00/lvol1" to a two-way mirror
+logical volume:
+.sp
+.B lvconvert \-m1 vg00/lvol1
 
-"lvconvert --mirrorlog core vg00/lvol1"
-.br
-converts a mirror with a disk log to a
-mirror with an in-memory log.
+Converts the linear logical volume "vg00/lvol1" to a two-way RAID1
+logical volume:
+.sp
+.B lvconvert \-\-type raid1 \-m1 vg00/lvol1
 
-"lvconvert --mirrorlog disk vg00/lvol1"
-.br
-converts a mirror with an in-memory log
-to a mirror with a disk log.
+Converts a mirror with a disk log to a mirror with an in-memory log:
+.sp
+.B lvconvert \-\-mirrorlog core vg00/lvol1
 
-"lvconvert -m0 vg00/lvol1"
-.br
-converts a mirror logical volume to a linear logical
-volume.
-.br
+Converts a mirror with an in-memory log to a mirror with a disk log:
+.sp
+.B lvconvert \-\-mirrorlog disk vg00/lvol1
 
-.br
-"lvconvert -s vg00/lvol1 vg00/lvol2"
-.br
-converts logical volume "vg00/lvol2" to snapshot of original volume "vg00/lvol1"
+Converts a mirror logical volume to a linear logical volume:
+.sp
+.B lvconvert \-m0 vg00/lvol1
 
-.br
-"lvconvert -m1 vg00/lvol1 /dev/sda:0-15 /dev/sdb:0-15"
-.br
-converts linear logical volume "vg00/lvol1" to a two-way mirror, using physical
-extents /dev/sda:0-15 and /dev/sdb:0-15 for allocation of new extents.
+Converts a mirror logical volume to a RAID1 logical volume with the same
+number of images:
+.sp
+.B lvconvert \-\-type raid1 vg00/mirror_lv
 
-.br
-"lvconvert -m0 vg00/lvmirror1 /dev/sda
-.br
-converts mirror logical volume "vg00/lvmirror1" to linear, freeing physical
-extents from /dev/sda.
+Converts logical volume "vg00/lvol2" to snapshot of original volume
+"vg00/lvol1":
+.sp
+.B lvconvert \-s vg00/lvol1 vg00/lvol2
 
-.br
-"lvconvert --merge vg00/lvol1_snap"
-.br
-merges "vg00/lvol1_snap" into its origin.
+Converts linear logical volume "vg00/lvol1" to a two-way mirror,
+using physical extents /dev/sda:0-15 and /dev/sdb:0-15 for allocation
+of new extents:
+.sp
+.B lvconvert \-m1 vg00/lvol1 /dev/sda:0-15 /dev/sdb:0-15
 
-.br
-"lvconvert --merge @some_tag"
-.br
-If vg00/lvol1, vg00/lvol2, and vg00/lvol3 are all tagged with "some_tag"
-each snapshot logical volume will be merged serially, e.g.: vg00/lvol1,
-then vg00/lvol2, then vg00/lvol3.  If --background were used it would start
+Converts mirror logical volume "vg00/lvmirror1" to linear, freeing physical
+extents from /dev/sda:
+.sp
+.B lvconvert \-m0 vg00/lvmirror1 /dev/sda
+
+Merges "vg00/lvol1_snap" into its origin:
+.sp
+.B lvconvert \-\-merge vg00/lvol1_snap
+
+If "vg00/lvol1", "vg00/lvol2" and "vg00/lvol3" are all tagged with "some_tag"
+each snapshot logical volume will be merged serially, 
+e.g.: "vg00/lvol1", then "vg00/lvol2", then "vg00/lvol3".
+If \-\-background were used it would start
 all snapshot logical volume merges in parallel.
+.sp
+.B lvconvert \-\-merge @some_tag
+
+Extracts one image from the mirror, making it a new logical volume named
+"lv_split".  The mirror the image is extracted from is reduced accordingly.
+If it was a 2-way mirror (created with '-m 1'), then the resulting original
+volume will be linear.
+.sp
+.B lvconvert \-\-splitmirrors 1 \-\-name lv_split vg00/lvmirror1
+
+A mirrored logical volume created with \-\-type raid1 can use the
+\-\-trackchanges argument when splitting off an image.
+Detach one image from the mirrored logical volume lv_raid1 as a separate
+read-only device and track the changes made to the mirror while it is detached.
+The split-off device has a name of the form lv_raid1_rimage_N, where N is
+a number, and it cannot be renamed.
+.sp
+.B lvconvert \-\-splitmirrors 1 \-\-trackchanges vg00/lv_raid1
+
+Merge an image that was detached temporarily from its mirror with
+the \-\-trackchanges argument back into its original mirror and
+bring its contents back up-to-date.
+.sp
+.B lvconvert \-\-merge vg00/lv_raid1_rimage_1
+
+Replaces the physical volume "/dev/sdb1" in the RAID1 logical volume "my_raid1"
+with the specified physical volume "/dev/sdf1".  Had the argument "/dev/sdf1"
+been left out, lvconvert would attempt to find a suitable device from those
+available in the volume group.
+.sp
+.B lvconvert \-\-replace /dev/sdb1 vg00/my_raid1 /dev/sdf1
 
 .SH SEE ALSO
 .BR lvm (8),
index 0d0976ff68203572b2f31263a4eca7b06f4695fd..fb54cc64aa202ca18cac97d2e9da60fa1d259204 100644 (file)
 lvcreate \- create a logical volume in an existing volume group
 .SH SYNOPSIS
 .B lvcreate
-[\-\-addtag Tag]
-[\-\-alloc AllocationPolicy]
-[\-A|\-\-autobackup y|n] [\-C|\-\-contiguous y|n] [\-d|\-\-debug]
-[\-h|\-?|\-\-help] [\-\-noudevsync]
-[\-\-ignoremonitoring]
-[\-\-monitor {y|n}]
-[\-i|\-\-stripes Stripes [\-I|\-\-stripesize StripeSize]]
-{\-l|\-\-extents LogicalExtentsNumber[%{VG|PVS|FREE}] |
- \-L|\-\-size LogicalVolumeSize[bBsSkKmMgGtTpPeE]}
-[\-M|\-\-persistent y|n] [\-\-minor minor]
-[\-m|\-\-mirrors Mirrors [\-\-nosync] [\-\-mirrorlog {disk|core|mirrored}] [\-\-corelog]
-[\-R|\-\-regionsize MirrorLogRegionSize]]
-[\-n|\-\-name LogicalVolumeName]
-[\-p|\-\-permission r|rw] [\-r|\-\-readahead ReadAheadSectors|auto|none]
-[\-t|\-\-test]
-[\-\-type SegmentType]
-[\-v|\-\-verbose] [\-Z|\-\-zero y|n]
-VolumeGroupName [PhysicalVolumePath[:PE[-PE]]...]
+.RB [ \-\-addtag
+.IR Tag ]
+.RB [ \-\-alloc
+.IR AllocationPolicy ]
+.RB [ \-a | \-\-activate
+.RI [ a | e | l ]{ y | n }]
+.RB [ \-A | \-\-autobackup
+.RI { y | n }]
+.RB [ \-C | \-\-contiguous
+.RI { y | n }]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-\-noudevsync ]
+.RB [ \-\-ignoremonitoring ]
+.RB [ \-\-monitor
+.RI { y | n }]
+.RB [ \-i | \-\-stripes
+.IR Stripes
+.RB [ \-I | \-\-stripesize
+.IR StripeSize ]]
+.RB {[ \-l | \-\-extents
+.IR LogicalExtentsNumber [ % { VG | PVS | FREE }]
+|
+.BR \-L | \-\-size
+.IR LogicalVolumeSize [ bBsSkKmMgGtTpPeE ]]
+|
+.BR \-V | \-\-virtualsize
+.IR VirtualSize [ bBsSkKmMgGtTpPeE ]}
+.RB [ \-M | \-\-persistent
+.RI { y | n }]
+.RB [ \-\-minor
+.IR minor ]
+.RB [ \-m | \-\-mirrors
+.IR Mirrors
+.RB [ \-\-nosync ]
+.RB [ \-\-mirrorlog
+.RI { disk | core | mirrored }
+|
+.BR \-\-corelog ]
+.RB [ \-R | \-\-regionsize
+.IR MirrorLogRegionSize ]]
+.RB [ \-n | \-\-name
+.IR LogicalVolume { Name | Path }]
+.RB [ \-p | \-\-permission
+.RI { r | rw }]
+.RB [ \-r | \-\-readahead
+.RI { ReadAheadSectors | auto | none }]
+.RB [ \-t | \-\-test ]
+.RB [ \-T | \-\-thin
+.RB [ \-c | \-\-chunksize
+.IR ChunkSize ]
+.RB [ \-\-discards
+.RI { ignore | nopassdown | passdown }]
+.RB [ \-\-poolmetadatasize
+.IR MetadataSize [ bBsSkKmMgG ]]]
+.RB [ \-\-thinpool
+.IR ThinPoolLogicalVolume { Name | Path }]
+.RB [ \-\-type
+.IR SegmentType ]
+.RB [ \-v | \-\-verbose ]
+.RB [ \-Z | \-\-zero
+.RI { y | n }]
+.IR VolumeGroup { Name | Path }[/ ThinPoolLogicalVolumeName ]
+.RI [ PhysicalVolumePath [ :PE [ -PE ]]...]
 .br
 
-.br
 .B lvcreate
-{\-l|\-\-extents LogicalExtentsNumber[%{VG|FREE|ORIGIN}] |
- \-L|\-\-size LogicalVolumeSize[bBsSkKmMgGtTpPeE]}
-[\-c|\-\-chunksize ChunkSize]
-[\-\-noudevsync]
-[\-\-ignoremonitoring]
-[\-\-monitor {y|n}]
-\-n|\-\-name SnapshotLogicalVolumeName
-{{\-s|\-\-snapshot}
-OriginalLogicalVolumePath | 
-[\-s|\-\-snapshot]
-VolumeGroupName \-\-virtualsize VirtualSize}
+.RB [ \-l | \-\-extents
+.IR LogicalExtentsNumber [ % { VG | FREE | ORIGIN }]
+|
+.BR \-L | \-\-size
+.IR LogicalVolumeSize [ bBsSkKmMgGtTpPeE ]]
+.RB [ \-c | \-\-chunksize
+.IR ChunkSize ]
+.RB [ \-\-noudevsync ]
+.RB [ \-\-ignoremonitoring ]
+.RB [ \-\-monitor " {" \fIy | \fIn }]
+.RB [ \-n | \-\-name
+.IR SnapshotLogicalVolume { Name | Path }]
+.BR \-s | \-\-snapshot
+.RI {[ VolumeGroup { Name | Path }/] OriginalLogicalVolumeName
+.BR \-V | \-\-virtualsize
+.IR VirtualSize [ bBsSkKmMgGtTpPeE ]}
+.br
+
 .SH DESCRIPTION
-lvcreate creates a new logical volume in a volume group ( see
-.B vgcreate(8), vgchange(8)
-by allocating logical extents from the free physical extent pool
+lvcreate creates a new logical volume in a volume group (see
+.BR vgcreate "(8), " vgchange (8))
+by allocating logical extents from the free physical extent pool
 of that volume group.  If there are not enough free physical extents then
-the volume group can be extended ( see
-.B vgextend(8)
-with other physical volumes or by reducing existing logical volumes
-of this volume group in size ( see
-.B lvreduce(8)
-). If you specify one or more PhysicalVolumes, allocation of physical
+the volume group can be extended (see
+.BR vgextend (8))
+with other physical volumes or by reducing existing logical volumes
+of this volume group in size (see
+.BR lvreduce (8)).
+If you specify one or more PhysicalVolumes, allocation of physical
 extents will be restricted to these volumes.
 .br
 .br
-The second form supports the creation of snapshot logical volumes which 
+The second form supports the creation of snapshot logical volumes which
 keep the contents of the original logical volume for backup purposes.
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See
+.BR lvm (8)
+for common options.
+.TP
+.IR \fB\-a ", " \fB\-\-activate " {" y | ay | n | ey | en | ly | ln }
+Controls the availability of the Logical Volumes for immediate use after
+the command finishes running.
+By default, new Logical Volumes are activated (\fB-a\fIy\fR).
+If it is possible technically, \fB-a\fIn\fR will leave the new Logical
+Volume inactive. But for example, snapshots can only be created
+in the active state so \fB\-a\fIn\fR cannot be used with \fB\-\-snapshot\fP.
+Normally the \fB\-\-zero n\fP argument has to be supplied too because
+zeroing (the default behaviour) also requires activation.
+If autoactivation option is used (\fB\-a\fIay\fR), the logical volume is
+activated only if it matches an item in the activation/auto_activation_volume_list
+set in lvm.conf. For autoactivated logical volumes, \fB\-\-zero n\fP is
+always assumed and it can't be overridden. If clustered locking is enabled,
+\fB\-a\fIey\fR will activate exclusively on one node and \fB\-a\fIly\fR will
+activate only on the local node.
 .TP
-.I \-c, \-\-chunksize ChunkSize
-Power of 2 chunk size for the snapshot logical volume between 4k and 512k.
+.BR \-c ", " \-\-chunksize " " \fIChunkSize
+Gives the size of chunk for snapshot and thin pool logical volumes.
+For snapshots the value must be power of 2 between 4KiB and 512KiB
+and the default value is 4.
+For thin pools the value must be between 64KiB and
+1048576KiB and the default value starts with 64 and scales
+up to fit the pool metadata size within 128MB,
+if the poolmetadata size is not specified.
+Older dm thin pool target version (<1.4) requires the value to be power of 2.
+The newer version requires to be the multiple of 64KiB, however discard is
+not supported for non power of 2 values.
+Default unit is in kilobytes.
 .TP
-.I \-C, \-\-contiguous y|n
+.BR \-C ", " \-\-contiguous " {" \fIy | \fIn }
 Sets or resets the contiguous allocation policy for
 logical volumes. Default is no contiguous allocation based
 on a next free principle.
 .TP
-.I \-i, \-\-stripes Stripes
+.BR \-\-discards " {" \fIignore | \fInopassdown | \fIpassdown }
+Set discards behavior.
+Default is \fIpassdown\fP.
+.TP
+.BR \-i ", " \-\-stripes " " \fIStripes
 Gives the number of stripes.
 This is equal to the number of physical volumes to scatter
 the logical volume.
 .TP
-.I \-I, \-\-stripesize StripeSize
+.BR \-I ", " \-\-stripesize " " \fIStripeSize
 Gives the number of kilobytes for the granularity of the stripes.
 .br
 StripeSize must be 2^n (n = 2 to 9) for metadata in LVM1 format.
 For metadata in LVM2 format, the stripe size may be a larger
 power of 2 but must not exceed the physical extent size.
 .TP
-.I \-l, \-\-extents LogicalExtentsNumber[%{VG|PVS|FREE|ORIGIN}]
+.IR \fB\-l ", " \fB\-\-extents " " LogicalExtentsNumber [ % { VG | PVS | FREE | ORIGIN }]
 Gives the number of logical extents to allocate for the new
 logical volume.
 The number can also be expressed as a percentage of the total space
-in the Volume Group with the suffix %VG, as a percentage of the
-remaining free space in the Volume Group with the suffix %FREE, as a
+in the Volume Group with the suffix \fI%VG\fR, as a percentage of the
+remaining free space in the Volume Group with the suffix \fI%FREE\fR, as a
 percentage of the remaining free space for the specified
-PhysicalVolume(s) with the suffix %PVS, or (for a snapshot) as a
+PhysicalVolume(s) with the suffix \fI%PVS\fR, or (for a snapshot) as a
 percentage of the total space in the Origin Logical Volume with the
-suffix %ORIGIN.
+suffix \fI%ORIGIN\fR.
 .TP
-.I \-L, \-\-size LogicalVolumeSize[bBsSkKmMgGtTpPeE]
+.IR \fB\-L ", " \fB\-\-size " " LogicalVolumeSize [ bBsSkKmMgGtTpPeE ]
 Gives the size to allocate for the new logical volume.
-A size suffix of K for kilobytes, M for megabytes,
-G for gigabytes, T for terabytes, P for petabytes
-or E for exabytes is optional.
+A size suffix of \fIK\fR for kilobytes, \fIM\fR for megabytes,
+\fIG\fR for gigabytes, \fIT\fR for terabytes, \fIP\fR for petabytes
+or \fIE\fR for exabytes is optional.
 .br
 Default unit is megabytes.
 .TP
-.I \-\-minor minor
+.B \-\-minor \fIminor
 Set the minor number.
 .TP
-.I \-M, \-\-persistent y|n
+.IR \fB\-M ", " \fB\-\-persistent " {" y | n }
 Set to y to make the minor number specified persistent.
 .TP
-.I \-m, \-\-mirrors Mirrors
+.BR \-m ", " \-\-mirrors " " \fIMirrors
 Creates a mirrored logical volume with Mirrors copies.  For example,
 specifying "-m 1" would result in a mirror with two-sides; that is, a
 linear volume plus one copy.
@@ -122,37 +206,43 @@ will create a persistent log that is itself mirrored.
 The optional argument --corelog is equivalent to --mirrorlog core.
 
 .TP
-.I \-n, \-\-name LogicalVolumeName
+.IR \fB\-n ", " \fB\-\-name " " LogicalVolume { Name | Path }
 The name for the new logical volume.
 .br
 Without this option a default names of "lvol#" will be generated where
 # is the LVM internal number of the logical volume.
 .TP
-.I \-\-noudevsync
+.B \-\-noudevsync
 Disable udev synchronisation. The
 process will not wait for notification from udev.
 It will continue irrespective of any possible udev processing
 in the background.  You should only use this if udev is not running
 or has rules that ignore the devices LVM2 creates.
 .TP
-.I \-\-monitor y|n
+.BR \-\-monitor " {" \fIy | \fIn }
 Start or avoid monitoring a mirrored or snapshot logical volume with
-dmeventd, if it is installed. 
+dmeventd, if it is installed.
 If a device used by a monitored mirror reports an I/O error,
-the failure is handled according to 
+the failure is handled according to
 \fBmirror_image_fault_policy\fP and \fBmirror_log_fault_policy\fP
 set in \fBlvm.conf\fP.
 .TP
-.I \-\-ignoremonitoring
+.B \-\-ignoremonitoring
 Make no attempt to interact with dmeventd unless \-\-monitor
 is specified.
 .TP
-.I \-p, \-\-permission r|rw
+.BR \-p ", " \-\-permission " {" \fIr | \fIrw }
 Set access permissions to read only or read and write.
 .br
 Default is read and write.
 .TP
-.I \-r, \-\-readahead ReadAheadSectors|auto|none
+.IR \fB\-\-poolmetadatasize " " MetadataSize [ bBsSkKmMgG ]
+Set the size of thin pool's metadata logical volume.
+Supported value is in range between 2MiB and 16GiB.
+Default value is  (Pool_LV_size / Pool_LV_chunk_size * 64b).
+Default unit is megabytes.
+.TP
+.IR \fB\-r ", " \fB\-\-readahead " {" ReadAheadSectors | auto | none }
 Set read ahead sector count of this logical volume.
 For volume groups with metadata in lvm1 format, this must
 be a value between 2 and 120.
@@ -160,23 +250,27 @@ The default value is "auto" which allows the kernel to choose
 a suitable value automatically.
 "None" is equivalent to specifying zero.
 .TP
-.I \-R, \-\-regionsize MirrorLogRegionSize
-A mirror is divided into regions of this size (in MB), and the mirror log 
+.BR \-R ", " \-\-regionsize " " \fIMirrorLogRegionSize
+A mirror is divided into regions of this size (in MB), and the mirror log
 uses this granularity to track which regions are in sync.
 .TP
-.I \-s, \-\-snapshot
+.IR \fB\-s ", " \fB\-\-snapshot " " OriginalLogicalVolume { Name | Path }
 Create a snapshot logical volume (or snapshot) for an existing, so called
 original logical volume (or origin).
 Snapshots provide a 'frozen image' of the contents of the origin
 while the origin can still be updated. They enable consistent
-backups and online recovery of removed/overwritten data/files. The snapshot
-does not need the same amount of storage the origin has. In a typical scenario,
-15-20% might be enough. In case the snapshot runs out of storage, use
-.B lvextend(8)
+backups and online recovery of removed/overwritten data/files.
+Thin snapshot is created when the origin is a thin volume and
+the size is not specified. Thin snapshot shares same blocks within
+the thin pool volume.
+The snapshot with the specified size does not need the same amount of
+storage the origin has. In a typical scenario, 15-20% might be enough.
+In case the snapshot runs out of storage, use
+.BR lvextend (8)
 to grow it. Shrinking a snapshot is supported by
-.B lvreduce(8)
+.BR lvreduce (8)
 as well. Run
-.B lvdisplay(8)
+.BR lvdisplay (8)
 on the snapshot in order to check how much data is allocated to it.
 Note that a small amount of the space you allocate to the snapshot is
 used to track the locations of the chunks of data, so you should
@@ -184,23 +278,38 @@ allocate slightly more space than you actually need and monitor the
 rate at which the snapshot data is growing so you can avoid running out
 of space.
 .TP
-.I \-\-type SegmentType
+.IR \fB\-T ", " \fB\-\-thin ", " \fB\-\-thinpool " " ThinPoolLogicalVolume { Name | Path }
+Creates thin pool or thin logical volume or both.
+Specifying the optional argument \fB\-\-size\fP will cause the creation of
+the thin pool logical volume.
+Specifying the optional argument \fB\-\-virtualsize\fP will cause
+the creation of the thin logical volume from given thin pool volume.
+Specifying both arguments will cause the creation of both
+thin pool and thin volume using this pool.
+Requires device mapper kernel driver for thin provisioning
+from kernel 3.2 or newer.
+.TP
+.B \-\-type \fISegmentType
 Create a logical volume that uses the specified segment type
-(e.g. "mirror", "snapshot", "striped").  Especially useful when no
-existing commandline switch alias enables the use of the desired type
-(e.g. "error" or "zero" types).  Many segment types already have a
-commandline switch alias that will enable their use (-s is an alias for
---type snapshot).
+(e.g. "raid5", "mirror", "snapshot", "thin", "thin-pool").
+Many segment types have a
+commandline switch alias that will enable their use
+(\fB\-s\fP is an alias for \fB\-\-type snapshot\fP).
+However, this argument must be used when no existing
+commandline switch alias is available for the desired type,
+as is the case with
+.IR error ", " zero ", " raid1 ", " raid4 ", " raid5 " or " raid6 .
 .TP
-.I \-\-virtualsize VirtualSize
-Create a sparse device of the given size (in MB by default) using a snapshot.  
+.BR \-V ", " \-\-virtualsize " " \fIVirtualSize [ \fIbBsSkKmMgGtTpPeE ]
+Create a sparse device of the given size (in MB by default) using a snapshot
+or thinly provisioned device when thin pool is specified.
 Anything written to the device will be returned when reading from it.
 Reading from other areas of the device will return blocks of zeros.
-It is implemented by creating a hidden virtual device of the
+Virtual snapshot is implemented by creating a hidden virtual device of the
 requested size using the zero target.  A suffix of _vorigin is used for
 this device.
 .TP
-.I \-Z, \-\-zero y|n
+.BR \-Z ", " \-\-zero " {" \fIy | \fIn }
 Controls zeroing of the first KB of data in the new logical volume.
 .br
 Default is yes.
@@ -213,46 +322,60 @@ Snapshot volumes are zeroed always.
 Warning: trying to mount an unzeroed logical volume can cause the system to
 hang.
 .SH Examples
-"lvcreate -i 3 -I 8 -L 100M vg00" tries to create a striped logical
-volume with 3 stripes, a stripesize of 8KB and a size of 100MB in the volume
-group named vg00. The logical volume name will be chosen by lvcreate.
+Creates a striped logical volume with 3 stripes, a stripesize of 8KB
+and a size of 100MB in the volume group named vg00.
+The logical volume name will be chosen by lvcreate:
+.sp
+.B lvcreate \-i 3 \-I 8 \-L 100M vg00
 
-"lvcreate -m1 -L 500M vg00" tries to create a mirror logical volume
-with 2 sides with a useable size of 500 MiB.  This operation would
-require 3 devices - two for the mirror devices and one for the disk
-log.
+Creates a mirror logical volume with 2 sides with a useable size of 500 MiB.
+This operation would require 3 devices (or option --alloc anywhere) - two
+for the mirror devices and one for the disk log:
+.sp
+.B lvcreate \-m1 \-L 500M vg00
 
-"lvcreate -m1 --mirrorlog core -L 500M vg00" tries to create a mirror logical volume
-with 2 sides with a useable size of 500 MiB.  This operation would
-require 2 devices - the log is "in-memory".
+Creates a mirror logical volume with 2 sides with a useable size of 500 MiB.
+This operation would require 2 devices - the log is "in-memory":
+.sp
+.B lvcreate \-m1 \-\-mirrorlog core \-L 500M vg00
 
-"lvcreate --size 100m --snapshot --name snap /dev/vg00/lvol1"
-.br
-creates a snapshot logical volume named /dev/vg00/snap which has access to the
+Creates a snapshot logical volume named /dev/vg00/snap which has access to the
 contents of the original logical volume named /dev/vg00/lvol1
 at snapshot logical volume creation time. If the original logical volume
 contains a file system, you can mount the snapshot logical volume on an
 arbitrary directory in order to access the contents of the filesystem to run
-a backup while the original filesystem continues to get updated.
+a backup while the original filesystem continues to get updated:
+.sp
+.B lvcreate \-\-size 100m \-\-snapshot \-\-name snap /dev/vg00/lvol1
 
-"lvcreate --virtualsize 1T --size 100M --snapshot --name sparse vg1"
-.br
-creates a sparse device named /dev/vg1/sparse of size 1TB with space for just
-under 100MB of actual data on it.
-.br
+Creates a sparse device named /dev/vg1/sparse of size 1TiB with space for just
+under 100MiB of actual data on it:
+.sp
+.B lvcreate \-\-virtualsize 1T \-\-size 100M \-\-snapshot \-\-name sparse vg1
 
-"lvcreate -L 64M -n lvol1 vg00 /dev/sda:0-7 /dev/sdb:0-7"
-.br
-creates a linear logical volume "vg00/lvol1" using physical extents
-/dev/sda:0-7 and /dev/sdb:0-7 for allocation of extents.
+Creates a linear logical volume "vg00/lvol1" using physical extents
+/dev/sda:0-7 and /dev/sdb:0-7 for allocation of extents:
+.sp
+.B lvcreate \-L 64M -n lvol1 vg00 /dev/sda:0\-7 /dev/sdb:0\-7
+
+Creates a 5GiB RAID5 logical volume "vg00/my_lv", with 3 stripes (plus
+a parity drive for a total of 4 devices) and a stripesize of 64KiB:
+.sp
+.B lvcreate \-\-type raid5 \-L 5G \-i 3 \-I 64 \-n my_lv vg00
 
+Creates 100MiB pool logical volume for thin provisioning
+build with 2 stripes 64KiB and chunk size 128KiB together with
+1TiB thin provisioned logical volume "vg00/thin_lv":
+.sp
+.B lvcreate \-i 2 \-I 64 \-c 256 \-L100M \-T vg00/pool \-V 1T \-\-name thin_lv
 
 .SH SEE ALSO
-.BR lvm (8), 
-.BR vgcreate (8), 
-.BR lvremove (8), 
+.BR lvm (8),
+.BR vgcreate (8),
+.BR lvchange (8),
+.BR lvremove (8),
 .BR lvrename (8)
-.BR lvextend (8), 
-.BR lvreduce (8), 
-.BR lvdisplay (8), 
+.BR lvextend (8),
+.BR lvreduce (8),
+.BR lvdisplay (8),
 .BR lvscan (8)
index 477e93499f96b1ec24882ce95c9dda7f8ce44cfa..99998490fef95bb326e0c9788cec60886d2995cc 100644 (file)
@@ -3,57 +3,70 @@
 lvdisplay \- display attributes of a logical volume
 .SH SYNOPSIS
 .B lvdisplay
-[\-a|\-\-all]
-[\-c|\-\-colon] [\-d|\-\-debug] [\-h|\-?|\-\-help]
-[\-\-ignorelockingfailure]
-[\-\-maps]
-[\-\-nosuffix]
-[\-P|\-\-partial]
-[\-\-units hHbBsSkKmMgGtTpPeE]
-[\-v|\-\-verbose]
-[\-\-version] [LogicalVolumePath [LogicalVolumePath...]]
+.RB [ \-a | \-\-all ]
+.RB [ \-c | \-\-colon ]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-\-ignorelockingfailure ]
+.RB [ \-\-maps ]
+.RB [ \-\-nosuffix ]
+.RB [ \-P | \-\-partial ]
+.RB [ \-\-units
+.IR hHbBsSkKmMgGtTpPeE ]
+.RB [ \-v | \-\-verbose ]
+.RB [ \-\-version ]
+.RI [ LogicalVolumePath
+.RI [ LogicalVolumePath ...]]
 .br
 
-.br
-.B lvdisplay \-\-columns | \-C
-[\-\-aligned]
-[\-a|\-\-all]
-[\-d|\-\-debug] [\-h|\-?|\-\-help]
-[\-\-ignorelockingfailure]
-[\-\-noheadings]
-[\-\-nosuffix]
-[\-o|\-\-options [+]Field[,Field]]
-[\-O|\-\-sort [+|-]Key1[,[+|-]Key2[,...]]]
-[\-P|\-\-partial]
-[\-\-segments]
-[\-\-separator Separator]
-[\-\-unbuffered]
-[\-\-units hHbBsSkKmMgGtTpPeE]
-[\-v|\-\-verbose]
-[\-\-version] [LogicalVolumePath [LogicalVolumePath...]]
+.B lvdisplay
+.BR \-\-columns | \-C
+.RB [ \-\-aligned ]
+.RB [ \-a | \-\-all ]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-\-ignorelockingfailure ]
+.RB [ \-\-noheadings ]
+.RB [ \-\-nosuffix ]
+.RB [ \-o | \-\-options
+.RI [ + ] Field [ ,Field ...]]
+.RB [ \-O | \-\-sort
+.RI [ + | - ] Key1 [ , [ + | - ] Key2 ...]]
+.RB [ \-P | \-\-partial ]
+.RB [ \-\-segments ]
+.RB [ \-\-separator
+.IR Separator ]
+.RB [ \-\-unbuffered ]
+.RB [ \-\-units
+.IR hHbBsSkKmMgGtTpPeE ]
+.RB [ \-v | \-\-verbose ]
+.RB [ \-\-version ]
+.RI [ LogicalVolumePath
+.RI [ LogicalVolumePath ...]]
 .SH DESCRIPTION
 lvdisplay allows you to see the attributes of a logical volume
 like size, read/write status, snapshot information etc.
 .P
-\fBlvs\fP (8) is an alternative that provides the same information 
-in the style of \fBps\fP (1).  \fBlvs\fP is recommended over
-\fBlvdisplay\fP.
+\fBlvs\fP(8) is an alternative that provides the same information
+in the style of \fBps\fP(1).
+\fBlvs\fP(8) is recommended over \fBlvdisplay\fP.
 
 .SH OPTIONS
-See \fBlvm\fP for common options and \fBlvs\fP for options given with
+See \fBlvm\fP(8) for common options and \fBlvs\fP for options given with
 \fB\-\-columns\fP.
 .TP
-.I \-\-all
+.B \-\-all
 Include information in the output about internal Logical Volumes that
 are components of normally-accessible Logical Volumes, such as mirrors,
 but which are not independently accessible (e.g. not mountable).
-For example, after creating a mirror using 'lvcreate -m1 --mirrorlog disk',
+For example, after creating a mirror using
+\fBlvcreate \-m1 \-\-mirrorlog disk\fP,
 this option will reveal three internal Logical Volumes, with suffixes
 mimage_0, mimage_1, and mlog.
 .TP
-.I \-c, \-\-colon
+.BR \-c ", " \-\-colon
 Generate colon separated output for easier parsing in scripts or programs.
-N.B. \fBlvs\fP (8) provides considerably more control over the output.
+N.B. \fBlvs\fP(8) provides considerably more control over the output.
 .nf
 
 The values are:
@@ -74,29 +87,30 @@ The values are:
 
 .fi
 .TP
-.I \-m, \-\-maps
+.BR \-m ", " \-\-maps
 Display the mapping of logical extents to physical volumes and
 physical extents.  To map physical extents
-to logical extents use
-.BR
-\fBpvs --segments -o+lv_name,seg_start_pe,segtype\fP.
+to logical extents use:
+.B pvs \-\-segments \-o+lv_name,seg_start_pe,segtype
 .TP
-.I \-\-columns | \-C
-Display output in columns, the equivalent of \fBlvs\fP.  Options listed
-are the same as options given in \fBlvs (8)\fP.
+.BR \-\-columns ", " \-C
+Display output in columns, the equivalent of \fBlvs\fP. Options listed
+are the same as options given in \fBlvs\fP(8).
 .SH Examples
-"lvdisplay -v /dev/vg00/lvol2" shows attributes of that logical volume.
-If snapshot
+Shows attributes of that logical volume. If snapshot
 logical volumes have been created for this original logical volume,
 this command shows a list of all snapshot logical volumes and their
-status (active or inactive) as well.
+status (active or inactive) as well:
+.sp
+.B lvdisplay \-v /dev/vg00/lvol2
 
-"lvdisplay /dev/vg00/snapshot" shows the attributes of this snapshot
-logical volume and also which original logical volume
-it is associated with.
+Shows the attributes of this snapshot logical volume and also which
+original logical volume it is associated with:
+.sp
+.B lvdisplay /dev/vg00/snapshot
 
 .SH SEE ALSO
-.BR lvm (8), 
-.BR lvcreate (8), 
+.BR lvm (8),
+.BR lvcreate (8),
 .BR lvscan (8),
 .BR pvs (8)
index 0b273ab7bcbf6831391be7020a511b2b27d1bb9f..ee62a2f5268cda2b826654ee609f32e3cb552748 100644 (file)
 lvextend \- extend the size of a logical volume
 .SH SYNOPSIS
 .B lvextend
-[\-\-alloc AllocationPolicy]
-[\-A|\-\-autobackup y|n] [\-d|\-\-debug] [\-h|\-?|\-\-help]
-[\-\-noudevsync]
-[\-i|\-\-stripes Stripes [\-I|\-\-stripesize StripeSize]]
-{\-l|\-\-extents [+]LogicalExtentsNumber[%{VG|LV|PVS|FREE|ORIGIN}] |
-\-L|\-\-size [+]LogicalVolumeSize[bBsSkKmMgGtTpPeE]}
-[\-f|\-\-force]
-[\-n|\-\-nofsck]
-[\-r|\-\-resizefs]
-[\-t|\-\-test]
-[\-v|\-\-verbose] LogicalVolumePath [PhysicalVolumePath[:PE[-PE]]...]
+.RB [ \-\-alloc
+.IR AllocationPolicy ]
+.RB [ \-A | \-\-autobackup
+.RI { y | n }]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-\-noudevsync]
+.RB [ \-i | \-\-stripes
+.I Stripes
+.RB [ \-I | \-\-stripesize
+.IR StripeSize ]]
+.RB { \-l | \-\-extents
+.RI [ + ] LogicalExtentsNumber [ % { VG | LV | PVS | FREE | ORIGIN }]
+|
+.BR \-L | \-\-size
+.RI [ + ] LogicalVolumeSize [ bBsSkKmMgGtTpPeE ]}
+.RB [ \-f | \-\-force ]
+.RB [ \-n | \-\-nofsck ]
+.RB [ \-r | \-\-resizefs ]
+.RB [ \-t | \-\-test ]
+.RB [ \-v | \-\-verbose ]
+.I LogicalVolumePath
+.RI [ PhysicalVolumePath [ :PE [ -PE ]]...]
 .SH DESCRIPTION
 lvextend allows you to extend the size of a logical volume.
 Extension of snapshot logical volumes (see
-.B lvcreate(8)
+.BR lvcreate (8)
 for information to create snapshots) is supported as well.
 But to change the number of copies in a mirrored logical
-volume use 
+volume use
 .BR lvconvert (8).
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .TP
-.I \-\-noudevsync
+.B \-\-noudevsync
 Disable udev synchronisation. The
 process will not wait for notification from udev.
 It will continue irrespective of any possible udev processing
 in the background.  You should only use this if udev is not running
 or has rules that ignore the devices LVM2 creates.
 .TP
-.I \-l, \-\-extents [+]LogicalExtentsNumber[%{VG|LV|PVS|FREE|ORIGIN}]
+.IR \fB\-l ", " \fB\-\-extents " [" + ] LogicalExtentsNumber [ % { VG | LV | PVS | FREE | ORIGIN }]
 Extend or set the logical volume size in units of logical extents.
-With the + sign the value is added to the actual size
+With the '\fI+\fP' sign the value is added to the actual size
 of the logical volume and without it, the value is taken as an absolute one.
 The number can also be expressed as a percentage of the total space
-in the Volume Group with the suffix %VG, relative to the existing
-size of the Logical Volume with the suffix %LV, of the remaining
-free space for the specified PhysicalVolume(s) with the suffix %PVS,
+in the Volume Group with the suffix \fI%VG\fP, relative to the existing
+size of the Logical Volume with the suffix \fI%LV\fP, of the remaining
+free space for the specified PhysicalVolume(s) with the suffix \fI%PVS\fP,
 as a percentage of the remaining free space in the Volume Group
-with the suffix %FREE, or (for a snapshot) as a percentage of the total
-space in the Origin Logical Volume with the suffix %ORIGIN.
+with the suffix \fI%FREE\fP, or (for a snapshot) as a percentage of the total
+space in the Origin Logical Volume with the suffix \fI%ORIGIN\fP.
+The resulting value is rounded upward.
 .TP
-.I \-L, \-\-size [+]LogicalVolumeSize[bBsSkKmMgGtTpPeE]
+.IR \fB\-L ", " \fB\-\-size " [" + ] LogicalVolumeSize [ bBsSkKmMgGtTpPeE ]
 Extend or set the logical volume size in units of megabytes.
 A size suffix of M for megabytes,
-G for gigabytes, T for terabytes, P for petabytes 
+G for gigabytes, T for terabytes, P for petabytes
 or E for exabytes is optional.
 With the + sign the value is added to the actual size
 of the logical volume and without it, the value is taken as an absolute one.
 .TP
-.I \-i, \-\-stripes Stripes
+.BR \-i ", " \-\-stripes " " \fIStripes
 Gives the number of stripes for the extension.
 Not applicable to LVs using the original metadata LVM format, which must
 use a single value throughout.
 .TP
-.I \-I, \-\-stripesize StripeSize
+.BR \-I ", " \-\-stripesize " " \fIStripeSize
 Gives the number of kilobytes for the granularity of the stripes.
 Not applicable to LVs using the original metadata LVM format, which must
 use a single value throughout.
 .br
 StripeSize must be 2^n (n = 2 to 9)
 .TP
-.I \-f, \-\-force
+.BR \-f ", " \-\-force
 Proceed with size extension without prompting.
 .TP
-.I \-n, \-\-nofsck
+.BR \-n ", " \-\-nofsck
 Do not perform fsck before extending filesystem when filesystem
-requires it. You may need to use \fB--force\fR to proceed with 
+requires it. You may need to use \fB\-\-force\fR to proceed with
 this option.
 .TP
-.I \-r, \-\-resizefs
-Resize underlying filesystem together with the logical volume using 
+.BR \-r ", " \-\-resizefs
+Resize underlying filesystem together with the logical volume using
 \fBfsadm\fR(8).
 .SH Examples
-"lvextend -L +54 /dev/vg01/lvol10 /dev/sdk3" tries to extend the size of
-that logical volume by 54MB on physical volume /dev/sdk3.
-This is only possible if /dev/sdk3 is a member of volume group vg01 and
-there are enough free physical extents in it.
+Extends the size of the logical volume "vg01/lvol10" by 54MiB on physical
+volume /dev/sdk3. This is only possible if /dev/sdk3 is a member of
+volume group vg01 and there are enough free physical extents in it:
+.sp
+.B lvextend -L +54 /dev/vg01/lvol10 /dev/sdk3
 
-"lvextend /dev/vg01/lvol01 /dev/sdk3" tries to extend the size of that
-logical volume by the amount of free space on physical volume /dev/sdk3.
-This is equivalent to specifying "-l +100%PVS" on the command line.
+Extends the size of logical volume "vg01/lvol01" by the amount of free
+space on physical volume /dev/sdk3. This is equivalent to specifying
+"-l +100%PVS" on the command line:
+.sp
+.B lvextend /dev/vg01/lvol01 /dev/sdk3
 
-.br
-"lvextend -L+16M vg01/lvol01 /dev/sda:8-9 /dev/sdb:8-9"
-.br
-tries to extend a logical volume "vg01/lvol01" by 16MB using physical extents
-/dev/sda:8-9 and /dev/sdb:8-9 for allocation of extents.
+Extends a logical volume "vg01/lvol01" by 16MiB using physical extents
+/dev/sda:8-9 and /dev/sdb:8-9 for allocation of extents:
+.sp
+.B lvextend -L+16M vg01/lvol01 /dev/sda:8-9 /dev/sdb:8-9
 
 .SH SEE ALSO
 .BR fsadm (8),
-.BR lvm (8), 
-.BR lvcreate (8), 
-.BR lvconvert (8), 
-.BR lvreduce (8), 
-.BR lvresize (8), 
+.BR lvm (8),
+.BR lvcreate (8),
+.BR lvconvert (8),
+.BR lvreduce (8),
+.BR lvresize (8),
 .BR lvchange (8)
index 37ebdab9b0288a891c8435c7a9baaed786afee48..2ce0065436f2b49eef9f7baf742b87dd039ebd75 100644 (file)
@@ -5,18 +5,18 @@ lvm \- LVM2 tools
 .B lvm
 [command | file]
 .SH DESCRIPTION
-\fBlvm\fP provides the command-line tools for LVM2.  A separate
+lvm provides the command-line tools for LVM2.  A separate
 manual page describes each command in detail.
 .LP
 If \fBlvm\fP is invoked with no arguments it presents a readline prompt
 (assuming it was compiled with readline support).
-LVM commands may be entered interactively at this prompt with 
-readline facilities including history and command name and option 
+LVM commands may be entered interactively at this prompt with
+readline facilities including history and command name and option
 completion.  Refer to \fBreadline\fP(3) for details.
 .LP
 If \fBlvm\fP is invoked with argv[0] set to the name of a specific
-LVM command (for example by using a hard or soft link) it acts as 
-that command.  
+LVM command (for example by using a hard or soft link) it acts as
+that command.
 .LP
 On invocation, \fBlvm\fP requires that only the standard file descriptors
 stdin, stdout and stderr are available.  If others are found, they
@@ -24,16 +24,16 @@ get closed and messages are issued warning about the leak.
 .LP
 Where commands take VG or LV names as arguments, the full path name is
 optional.  An LV called "lvol0" in a VG called "vg0" can be specified
-as "vg0/lvol0".  Where a list of VGs is required but is left empty, 
+as "vg0/lvol0".  Where a list of VGs is required but is left empty,
 a list of all VGs will be substituted.  Where a list of LVs is required
 but a VG is given, a list of all the LVs in that VG will be substituted.
-So "lvdisplay vg0" will display all the LVs in "vg0".
-Tags can also be used - see \fBaddtag\fP below.
+So \fBlvdisplay vg0\fP will display all the LVs in "vg0".
+Tags can also be used - see \fB\-\-addtag\fP below.
 .LP
-One advantage of using the built-in shell is that configuration 
-information gets cached internally between commands.  
+One advantage of using the built-in shell is that configuration
+information gets cached internally between commands.
 .LP
-A file containing a simple script with one command per line 
+A file containing a simple script with one command per line
 can also be given on the command line.  The script can also be
 executed directly if the first line is #! followed by the absolute
 path of \fBlvm\fP.
@@ -41,8 +41,8 @@ path of \fBlvm\fP.
 The following commands are built into lvm without links normally
 being created in the filesystem for them.
 .TP
-\fBdumpconfig\fP \(em Display the configuration information after 
-loading \fBlvm.conf\fP (5) and any other configuration files.
+\fBdumpconfig\fP \(em Display the configuration information after
+loading \fBlvm.conf\fP(5) and any other configuration files.
 .TP
 \fBformats\fP \(em Display recognised metadata formats.
 .TP
@@ -50,234 +50,309 @@ loading \fBlvm.conf\fP (5) and any other configuration files.
 .TP
 \fBpvdata\fP \(em Not implemented in LVM2.
 .TP
-\fBsegtypes\fP \(em Display recognised logical volume segment types.
+\fBsegtypes\fP \(em Display recognised Logical Volume segment types.
 .TP
 \fBversion\fP \(em Display version information.
 .LP
 .SH COMMANDS
 The following commands implement the core LVM functionality.
 .TP
-\fBpvchange\fP \(em Change attributes of a physical volume.
+\fBpvchange\fP \(em Change attributes of a Physical Volume.
 .TP
-\fBpvck\fP \(em Check physical volume metadata.
+\fBpvck\fP \(em Check Physical Volume metadata.
 .TP
 \fBpvcreate\fP \(em Initialize a disk or partition for use by LVM.
 .TP
-\fBpvdisplay\fP \(em Display attributes of a physical volume.
+\fBpvdisplay\fP \(em Display attributes of a Physical Volume.
 .TP
-\fBpvmove\fP \(em Move physical extents.
+\fBpvmove\fP \(em Move Physical Extents.
 .TP
-\fBpvremove\fP \(em Remove a physical volume.
+\fBpvremove\fP \(em Remove a Physical Volume.
 .TP
 \fBpvresize\fP \(em Resize a disk or partition in use by LVM2.
 .TP
-\fBpvs\fP \(em Report information about physical volumes.
+\fBpvs\fP \(em Report information about Physical Volumes.
 .TP
-\fBpvscan\fP \(em Scan all disks for physical volumes.
+\fBpvscan\fP \(em Scan all disks for Physical Volumes.
 .TP
-\fBvgcfgbackup\fP \(em Backup volume group descriptor area.
+\fBvgcfgbackup\fP \(em Backup Volume Group descriptor area.
 .TP
-\fBvgcfgrestore\fP \(em Restore volume group descriptor area.
+\fBvgcfgrestore\fP \(em Restore Volume Group descriptor area.
 .TP
-\fBvgchange\fP \(em Change attributes of a volume group.
+\fBvgchange\fP \(em Change attributes of a Volume Group.
 .TP
-\fBvgck\fP \(em Check volume group metadata.
+\fBvgck\fP \(em Check Volume Group metadata.
 .TP
-\fBvgconvert\fP \(em Convert volume group metadata format.
+\fBvgconvert\fP \(em Convert Volume Group metadata format.
 .TP
-\fBvgcreate\fP \(em Create a volume group.
+\fBvgcreate\fP \(em Create a Volume Group.
 .TP
-\fBvgdisplay\fP \(em Display attributes of volume groups.
+\fBvgdisplay\fP \(em Display attributes of Volume Groups.
 .TP
-\fBvgexport\fP \(em Make volume groups unknown to the system.
+\fBvgexport\fP \(em Make volume Groups unknown to the system.
 .TP
-\fBvgextend\fP \(em Add physical volumes to a volume group.
+\fBvgextend\fP \(em Add Physical Volumes to a Volume Group.
 .TP
-\fBvgimport\fP \(em Make exported volume groups known to the system.
+\fBvgimport\fP \(em Make exported Volume Groups known to the system.
 .TP
-\fBvgimportclone\fP \(em Import and rename duplicated volume group (e.g. a hardware snapshot).
+\fBvgimportclone\fP \(em Import and rename duplicated Volume Group (e.g. a hardware snapshot).
 .TP
-\fBvgmerge\fP \(em Merge two volume groups.
+\fBvgmerge\fP \(em Merge two Volume Groups.
 .TP
-\fBvgmknodes\fP \(em Recreate volume group directory and logical volume special files
+\fBvgmknodes\fP \(em Recreate Volume Group directory and Logical Volume special files
 .TP
-\fBvgreduce\fP \(em Reduce a volume group by removing one or more physical volumes.
+\fBvgreduce\fP \(em Reduce a Volume Group by removing one or more
+Physical Volumes.
 .TP
-\fBvgremove\fP \(em Remove a volume group.
+\fBvgremove\fP \(em Remove a Volume Group.
 .TP
-\fBvgrename\fP \(em Rename a volume group.
+\fBvgrename\fP \(em Rename a Volume Group.
 .TP
-\fBvgs\fP \(em Report information about volume groups.
+\fBvgs\fP \(em Report information about Volume Groups.
 .TP
-\fBvgscan\fP \(em Scan all disks for volume groups and rebuild caches.
+\fBvgscan\fP \(em Scan all disks for Volume Groups and rebuild caches.
 .TP
-\fBvgsplit\fP \(em Split a volume group into two, moving any logical volumes from one volume group to another by moving entire physical volumes.
+\fBvgsplit\fP \(em Split a Volume Group into two, moving any logical
+volumes from one Volume Group to another by moving entire Physical
+Volumes.
 .TP
-\fBlvchange\fP \(em Change attributes of a logical volume.
+\fBlvchange\fP \(em Change attributes of a Logical Volume.
 .TP
-\fBlvconvert\fP \(em Convert a logical volume from linear to mirror or snapshot.
+\fBlvconvert\fP \(em Convert a Logical Volume from linear to mirror or snapshot.
 .TP
-\fBlvcreate\fP \(em Create a logical volume in an existing volume group.
+\fBlvcreate\fP \(em Create a Logical Volume in an existing Volume Group.
 .TP
-\fBlvdisplay\fP \(em Display attributes of a logical volume.
+\fBlvdisplay\fP \(em Display attributes of a Logical Volume.
 .TP
-\fBlvextend\fP \(em Extend the size of a logical volume.
+\fBlvextend\fP \(em Extend the size of a Logical Volume.
 .TP
-\fBlvmchange\fP \(em Change attributes of the logical volume manager.
+\fBlvmchange\fP \(em Change attributes of the Logical Volume Manager.
 .TP
 \fBlvmdiskscan\fP \(em Scan for all devices visible to LVM2.
 .TP
 \fBlvmdump\fP \(em Create lvm2 information dumps for diagnostic purposes.
 .TP
-\fBlvreduce\fP \(em Reduce the size of a logical volume.
+\fBlvreduce\fP \(em Reduce the size of a Logical Volume.
 .TP
-\fBlvremove\fP \(em Remove a logical volume.
+\fBlvremove\fP \(em Remove a Logical Volume.
 .TP
-\fBlvrename\fP \(em Rename a logical volume.
+\fBlvrename\fP \(em Rename a Logical Volume.
 .TP
-\fBlvresize\fP \(em Resize a logical volume.
+\fBlvresize\fP \(em Resize a Logical Volume.
 .TP
-\fBlvs\fP \(em Report information about logical volumes.
+\fBlvs\fP \(em Report information about Logical Volumes.
 .TP
-\fBlvscan\fP \(em Scan (all disks) for logical volumes.
+\fBlvscan\fP \(em Scan (all disks) for Logical Volumes.
 .TP
 The following commands are not implemented in LVM2 but might be in the future: lvmsadc, lvmsar, pvdata.
 .SH OPTIONS
-The following options are available for many of the commands. 
-They are implemented generically and documented here rather 
+The following options are available for many of the commands.
+They are implemented generically and documented here rather
 than repeated on individual manual pages.
 .TP
-\fB-h | --help\fP \(em Display the help text.
+.BR \-h ", " \-\-help
+Display the help text.
 .TP
-\fB--version\fP \(em Display version information.
+.B \-\-version
+Display version information.
 .TP
-\fB-v | --verbose\fP \(em Set verbose level.
-Repeat from 1 to 3 times to increase the detail of messages 
-sent to stdout and stderr.  Overrides config file setting.
+.BR \-v ", " \-\-verbose
+Set verbose level. Repeat from 1 to 3 times to increase the detail
+of messages sent to stdout and stderr.  Overrides config file setting.
 .TP
-\fB-d | --debug\fP \(em Set debug level.
-Repeat from 1 to 6 times to increase the detail of messages sent 
-to the log file and/or syslog (if configured).
+.BR \-d ", " \-\-debug
+Set debug level. Repeat from 1 to 6 times to increase the detail of
+messages sent to the log file and/or syslog (if configured).
 Overrides config file setting.
 .TP
-\fB--quiet\fP \(em Suppress output and log messages.
-Overrides -d and -v.
+.BR \-q ", "  \-\-quiet
+Suppress output and log messages.
+Overrides \fB\-d\fP and \fB\-v\fP.
 .TP
-\fB-t | --test\fP \(em Run in test mode.
-Commands will not update metadata.
+.BR \-t ", " \-\-test
+Run in test mode. Commands will not update metadata.
 This is implemented by disabling all metadata writing but nevertheless
 returning success to the calling function.  This may lead to unusual
 error messages in multi-stage operations if a tool relies on reading
 back metadata it believes has changed but hasn't.
 .TP
-\fB--driverloaded\fP { \fBy\fP | \fBn\fP }
+.BR \-\-driverloaded " {" \fIy | \fIn }
 Whether or not the device-mapper kernel driver is loaded.
-If you set this to \fBn\fP, no attempt will be made to contact the driver.
+If you set this to \fIn\fP, no attempt will be made to contact the driver.
 .TP
-\fB-A | --autobackup\fP { \fBy\fP | \fBn\fP }
-Whether or not to metadata should be backed up automatically after a change.  
+.BR \-A ", " \-\-autobackup " {" \fIy | \fIn }
+Whether or not to metadata should be backed up automatically after a change.
 You are strongly advised not to disable this!
-See
-.B vgcfgbackup (8).
+See \fBvgcfgbackup\fP(8).
 .TP
-\fB-P | --partial\fP
-When set, the tools will do their best to provide access to volume groups
-that are only partially available (one or more physical volumes belonging
-to the volume group are missing from the system).  Where part of a logical
+.BR \-P ", " \-\-partial
+When set, the tools will do their best to provide access to Volume Groups
+that are only partially available (one or more Physical Volumes belonging
+to the Volume Group are missing from the system).  Where part of a logical
 volume is missing, \fB/dev/ioerror\fP will be substituted, and you could use
-\fBdmsetup (8)\fP to set this up to return I/O errors when accessed,
+\fBdmsetup\fP(8) to set this up to return I/O errors when accessed,
 or create it as a large block device of nulls.  Metadata may not be
-changed with this option. To insert a replacement physical volume
-of the same or large size use \fBpvcreate -u\fP to set the uuid to 
-match the original followed by \fBvgcfgrestore (8)\fP.
+changed with this option. To insert a replacement Physical Volume
+of the same or large size use \fBpvcreate \-u\fP to set the uuid to
+match the original followed by \fBvgcfgrestore\fP(8).
 .TP
-\fB-M | --metadatatype type\fP
-Specifies which type of on-disk metadata to use, such as \fBlvm1\fP 
-or \fBlvm2\fP, which can be abbreviated to \fB1\fP or \fB2\fP respectively.
-The default (lvm2) can be changed by setting \fBformat\fP in the \fBglobal\fP
-section of the config file.
+.BR \-M ", " \-\-metadatatype " " \fIType
+Specifies which type of on-disk metadata to use, such as \fIlvm1\fP
+or \fIlvm2\fP, which can be abbreviated to \fI1\fP or \fI2\fP respectively.
+The default (\fIlvm2\fP) can be changed by setting \fBformat\fP
+in the \fBglobal\fP section of the config file.
 .TP
-\fB--ignorelockingfailure\fP
+.B \-\-ignorelockingfailure
 This lets you proceed with read-only metadata operations such as
-\fBlvchange -ay\fP and \fBvgchange -ay\fP even if the locking module fails.
-One use for this is in a system init script if the lock directory 
+\fBlvchange \-ay\fP and \fBvgchange \-ay\fP even if the locking module fails.
+One use for this is in a system init script if the lock directory
 is mounted read-only when the script runs.
 .TP
-\fB--addtag tag\fP
-Add the tag \fBtag\fP to a PV, VG or LV.  
+.B \-\-addtag \fITag
+Add the tag \fITag\fP to a PV, VG or LV.
 Supply this argument multiple times to add more than one tag at once.
-A tag is a word that can be used to group LVM2 objects of the same type 
-together. 
-Tags can be given on the command line in place of PV, VG or LV 
+A tag is a word that can be used to group LVM2 objects of the same type
+together.
+Tags can be given on the command line in place of PV, VG or LV
 arguments.  Tags should be prefixed with @ to avoid ambiguity.
 Each tag is expanded by replacing it with all objects possessing
 that tag which are of the type expected by its position on the command line.
 PVs can only possess tags while they are part of a Volume Group:
 PV tags are discarded if the PV is removed from the VG.
-As an example, you could tag some LVs as \fBdatabase\fP and others 
-as \fBuserdata\fP and then activate the database ones 
-with \fBlvchange -ay @database\fP.
+As an example, you could tag some LVs as \fBdatabase\fP and others
+as \fBuserdata\fP and then activate the database ones
+with \fBlvchange \-ay @database\fP.
 Objects can possess multiple tags simultaneously.
 Only the new LVM2 metadata format supports tagging: objects using the
 LVM1 metadata format cannot be tagged because the on-disk format does not
 support it.
-Snapshots cannot be tagged.
-Characters allowed in tags are: A-Z a-z 0-9 _ + . - and 
-as of version 2.02.78 the following characters are also
-accepted: / = ! : # &
+Characters allowed in tags are:
+.B A-Z a-z 0-9 _ + . -
+and as of version 2.02.78 the following characters are also accepted:
+.B / = ! : # &
 .TP
-\fB--deltag tag\fP
-Delete the tag \fBtag\fP from a PV, VG or LV, if it's present.
+.B \-\-deltag \fITag
+Delete the tag \fITag\fP from a PV, VG or LV, if it's present.
 Supply this argument multiple times to remove more than one tag at once.
 .TP
-\fB--alloc AllocationPolicy\fP
-The allocation policy to use: \fBcontiguous\fP, \fBcling\fP, \fBnormal\fP, \fBanywhere\fP or \fBinherit\fP.
-When a command needs to allocate physical extents from the volume group,
-the allocation policy controls how they are chosen.  
-Each volume group and logical volume has an allocation policy.
-The default for a volume group is \fBnormal\fP which applies
+.B \-\-alloc \fIAllocationPolicy
+The allocation policy to use:
+.IR contiguous ,
+.IR cling ,
+.IR normal ,
+.IR anywhere " or"
+.IR inherit .
+When a command needs to allocate Physical Extents from the Volume Group,
+the allocation policy controls how they are chosen.
+Each Volume Group and Logical Volume has an allocation policy defined.
+The default for a Volume Group is \fInormal\fP which applies
 common-sense rules such as not placing parallel stripes on the same
-physical volume.  The default for a logical volume is \fBinherit\fP
-which applies the same policy as for the volume group.  These policies can
-be changed using \fBlvchange\fP (8) and \fBvgchange\fP (8) or over-ridden
+Physical Volume.  The default for a Logical Volume is \fIinherit\fP
+which applies the same policy as for the Volume Group.  These policies can
+be changed using \fBlvchange\fP(8) and \fBvgchange\fP(8) or overridden
 on the command line of any command that performs allocation.
-The \fBcontiguous\fP policy requires that new extents be placed adjacent
-to existing extents. 
-The \fBcling\fP policy places new extents on the same physical
-volume as existing extents in the same stripe of the Logical Volume.
-If there are sufficient free extents to satisfy
-an allocation request but \fBnormal\fP doesn't use them,
-\fBanywhere\fP will - even if that reduces performance by
-placing two stripes on the same physical volume.
-.IP
-N.B. The policies described above are not implemented fully yet.
-In particular, contiguous free space cannot be broken up to
-satisfy allocation attempts.
+The \fIcontiguous\fP policy requires that new Physical Extents be placed adjacent
+to existing Physical Extents.
+The \fIcling\fP policy places new Physical Extents on the same Physical
+Volume as existing Physical Extents in the same stripe of the Logical Volume.
+If there are sufficient free Physical Extents to satisfy
+an allocation request but \fInormal\fP doesn't use them,
+\fIanywhere\fP will - even if that reduces performance by
+placing two stripes on the same Physical Volume.
 .SH ENVIRONMENT VARIABLES
 .TP
-\fBLVM_SYSTEM_DIR\fP 
-Directory containing lvm.conf and other LVM
-system files.
-Defaults to "#DEFAULT_SYS_DIR#".
+.B HOME
+Directory containing \fI.lvm_history\fP if the internal readline
+shell is invoked.
 .TP
-\fBHOME\fP 
-Directory containing .lvm_history if the internal readline shell
-is invoked.
+.B LVM_SYSTEM_DIR
+Directory containing \fBlvm.conf\fP(5) and other LVM system files.
+Defaults to "#DEFAULT_SYS_DIR#".
 .TP
-\fBLVM_VG_NAME\fP 
-The volume group name that is assumed for 
-any reference to a logical volume that doesn't specify a path.
+.B LVM_VG_NAME
+The Volume Group name that is assumed for
+any reference to a Logical Volume that doesn't specify a path.
 Not set by default.
 .SH VALID NAMES
 The following characters are valid for VG and LV names:
-\fBa-z A-Z 0-9 + _ . -\fP
+.B a-z A-Z 0-9 + _ . -
 .LP
 VG and LV names cannot begin with a hyphen.
 There are also various reserved names that are used internally by lvm that can not be used as LV or VG names.
 A VG cannot be called anything that exists in /dev/ at the time of creation, nor can it be called '.' or '..'.
-A LV cannot be called '.' '..' 'snapshot' or 'pvmove'. The LV name may also not contain the strings '_mlog' or '_mimage'
+A LV cannot be called '.' '..' 'snapshot' or 'pvmove'. The LV name may also not contain
+the strings '_mlog', '_mimage', '_rimage', '_tdata', '_tmeta'.
+.SH ALLOCATION
+When an operation needs to allocate Physical Extents for one or more
+Logical Volumes, the tools proceed as follows:
+
+First of all, they generate the complete set of unallocated Physical Extents
+in the Volume Group.  If any ranges of Physical Extents are supplied at
+the end of the command line, only unallocated Physical Extents within
+those ranges on the specified Physical Volumes are considered.
+
+Then they try each allocation policy in turn, starting with the strictest
+policy (\fIcontiguous\fP) and ending with the allocation policy specified
+using \fB\-\-alloc\fP or set as the default for the particular Logical
+Volume or Volume Group concerned.  For each policy, working from the
+lowest-numbered Logical Extent of the empty Logical Volume space that
+needs to be filled, they allocate as much space as possible according to
+the restrictions imposed by the policy.  If more space is needed,
+they move on to the next policy.
+
+The restrictions are as follows:
+
+\fIContiguous\fP requires that the physical location of any Logical
+Extent that is not the first Logical Extent of a Logical Volume is
+adjacent to the physical location of the Logical Extent immediately
+preceding it.
+
+\fICling\fP requires that the Physical Volume used for any Logical
+Extent to be added to an existing Logical Volume is already in use by at
+least one Logical Extent earlier in that Logical Volume.  If the
+configuration parameter allocation/cling_tag_list is defined, then two
+Physical Volumes are considered to match if any of the listed tags is
+present on both Physical Volumes.  This allows groups of Physical
+Volumes with similar properties (such as their physical location) to be
+tagged and treated as equivalent for allocation purposes.
 
+When a Logical Volume is striped or mirrored, the above restrictions are
+applied independently to each stripe or mirror image (leg) that needs
+space.
 
+\fINormal\fP will not choose a Physical Extent that shares the same Physical
+Volume as a Logical Extent already allocated to a parallel Logical
+Volume (i.e. a different stripe or mirror image/leg) at the same offset 
+within that parallel Logical Volume.
+
+When allocating a mirror log at the same time as Logical Volumes to hold
+the mirror data, Normal will first try to select different Physical
+Volumes for the log and the data.  If that's not possible and the
+allocation/mirror_logs_require_separate_pvs configuration parameter is
+set to 0, it will then allow the log to share Physical Volume(s) with
+part of the data.  
+
+When allocating thin pool metadata, similar considerations to those of a
+mirror log in the last paragraph apply based on the value of the
+allocation/thin_pool_metadata_require_separate_pvs configuration
+parameter.
+
+If you rely upon any layout behaviour beyond that documented here, be
+aware that it might change in future versions of the code.  
+
+For example, if you supply on the command line two empty Physical
+Volumes that have an identical number of free Physical Extents available for
+allocation, the current code considers using each of them in the order
+they are listed, but there is no guarantee that future releases will
+maintain that property.  If it is important to obtain a specific layout
+for a particular Logical Volume, then you should build it up through a
+sequence of \fBlvcreate\fP(8) and \fBlvconvert\fP(8) steps such that the
+restrictions described above applied to each step leave the tools no
+discretion over the layout.
+
+To view the way the allocation process currently works in any specific
+case, read the debug logging output, for example by adding \-vvvv to
+a command.
 .SH DIAGNOSTICS
 All tools return a status code of zero on success or non-zero on failure.
 .SH FILES
@@ -325,4 +400,3 @@ All tools return a status code of zero on success or non-zero on failure.
 .BR vgsplit (8),
 .BR readline (3),
 .BR lvm.conf (5)
-
index ac16b1d59792ad28c621147882138003b5bb1c30..79044fcc6d3d275c333164c801938ddf4cbdf03d 100644 (file)
@@ -4,35 +4,35 @@ lvm.conf \- Configuration file for LVM2
 .SH SYNOPSIS
 .B #DEFAULT_SYS_DIR#/lvm.conf
 .SH DESCRIPTION
-lvm.conf is loaded during the initialisation phase of 
-\fBlvm\fP (8).  This file can in turn lead to other files
+lvm.conf is loaded during the initialisation phase of
+\fBlvm\fP(8).  This file can in turn lead to other files
 being loaded - settings read in later override earlier
-settings.  File timestamps are checked between commands and if 
-any have changed, all the files are reloaded.  
+settings.  File timestamps are checked between commands and if
+any have changed, all the files are reloaded.
 .LP
 Use \fBlvm dumpconfig\fP to check what settings are in use.
 .SH SYNTAX
 .LP
 This section describes the configuration file syntax.
 .LP
-Whitespace is not significant unless it is within quotes. 
+Whitespace is not significant unless it is within quotes.
 This provides a wide choice of acceptable indentation styles.
 Comments begin with # and continue to the end of the line.
 They are treated as whitespace.
 .LP
 Here is an informal grammar:
 .TP
-\fBfile = value*\fP
+.BR file " = " value *
 .br
 A configuration file consists of a set of values.
 .TP
-\fBvalue = section | assignment\fP
+.BR value " = " section " | " assignment
 .br
 A value can either be a new section, or an assignment.
 .TP
-\fBsection = identifier '{' value* '}'\fP
+.BR section " = " identifier " '" { "' " value "* '" } '
 .br
-A section is groups associated values together.  
+A section is groups associated values together.
 .br
 It is denoted by a name and delimited by curly brackets.
 .br
@@ -42,27 +42,27 @@ e.g.        backup {
 .br
        }
 .TP
-\fBassignment = identifier '=' (array | type)\fP
+.BR assignment " = " identifier " '" = "' ( " array " | " type " )"
 .br
 An assignment associates a type with an identifier.
 .br
 e.g.   max_archives = 42
 .br
 .TP
-\fBarray = '[' (type ',')* type ']' | '[' ']'\fP
+.BR array " =  '" [ "' ( " type " '" , "')* " type " '" ] "' | '" [ "' '" ] '
 .br
-Inhomogeneous arrays are supported. 
+Inhomogeneous arrays are supported.
 .br
-Elements must be separated by commas.  
+Elements must be separated by commas.
 .br
 An empty array is acceptable.
 .TP
-\fBtype = integer | float | string\fP
-\fBinteger = [0-9]*\fP
+.BR type " = " integer " | " float " | " string
+.BR integer " = [0-9]*"
 .br
-\fBfloat = [0-9]*\.[0-9]*\fP
+.BR float " = [0-9]*'" . '[0-9]*
 .br
-\fBstring = '"' .* '"'\fP
+.B string \fR= '\fB"\fR'.*'\fB"\fR'
 .IP
 Strings must be enclosed in double quotes.
 
@@ -73,10 +73,10 @@ The sections that may be present in the file are:
 \fBdevices\fP \(em Device settings
 .IP
 \fBdir\fP \(em Directory in which to create volume group device nodes.
-Defaults to "/dev".  Commands also accept this as a prefix on volume 
+Defaults to "/dev".  Commands also accept this as a prefix on volume
 group names.
 .IP
-\fBscan\fP \(em List of directories to scan recursively for 
+\fBscan\fP \(em List of directories to scan recursively for
 LVM physical volumes.
 Devices in directories outside this hierarchy will be ignored.
 Defaults to "/dev".
@@ -97,40 +97,40 @@ will be accepted or rejected (ignored).  Devices that don't match
 any patterns are accepted. If you want to reject patterns that
 don't match, end the list with "r/.*/".
 If there are several names for the same device (e.g. symbolic links
-in /dev), if any name matches any \fBa\fP pattern, the
-device is accepted; otherwise if any name matches any \fBr\fP
-pattern it is rejected; otherwise it is accepted.
-As an example, to ignore /dev/cdrom you could use:
+in /dev), if the first matching pattern in the list for any of the names is an
+\fBa\fP pattern, the device is accepted; otherwise if the first matching
+pattern in the list for any of the names is an \fBr\fP pattern it is rejected;
+otherwise it is accepted.  As an example, to ignore /dev/cdrom you could use:
 .br
-\fBdevices { filter=["r|cdrom|"] }\fP 
+\fBdevices { filter=["r|cdrom|"] }\fP
 .IP
 \fBcache_dir\fP \(em Persistent filter cache file directory.
 Defaults to "#DEFAULT_CACHE_DIR#".
 .IP
-\fBwrite_cache_state\fP \(em Set to 0 to disable the writing out of the 
+\fBwrite_cache_state\fP \(em Set to 0 to disable the writing out of the
 persistent filter cache file when \fBlvm\fP exits.
 Defaults to 1.
 .IP
 \fBtypes\fP \(em List of pairs of additional acceptable block device types
 found in /proc/devices together with maximum (non-zero) number of
-partitions (normally 16).  By default, LVM2 supports ide, sd, md, loop, 
+partitions (normally 16).  By default, LVM2 supports ide, sd, md, loop,
 dasd, dac960, nbd, ida, cciss, ubd, ataraid, drbd, power2, i2o_block
 and iseries/vd.  Block devices with major
-numbers of different types are ignored by LVM2.  
+numbers of different types are ignored by LVM2.
 Example: \fBtypes = ["fd", 16]\fP.
 To create physical volumes on device-mapper volumes
 created outside LVM2, perhaps encrypted ones from \fBcryptsetup\fP,
 you'll need \fBtypes = ["device-mapper", 16]\fP.  But if you do this,
-be careful to avoid recursion within LVM2.  The figure for number 
+be careful to avoid recursion within LVM2.  The figure for number
 of partitions is not currently used in LVM2 - and might never be.
 .IP
-\fBsysfs_scan\fP \(em If set to 1 and your kernel supports sysfs and 
+\fBsysfs_scan\fP \(em If set to 1 and your kernel supports sysfs and
 it is mounted, sysfs will be used as a quick way of filtering out
 block devices that are not present.
 .IP
 \fBmd_component_detection\fP \(em If set to 1, LVM2 will ignore devices
 used as components of software RAID (md) devices by looking for md
-superblocks. This doesn't always work satisfactorily e.g. if a device 
+superblocks. This doesn't always work satisfactorily e.g. if a device
 has been reused without wiping the md superblocks first.
 .IP
 \fBmd_chunk_alignment\fP \(em If set to 1, and a Physical Volume is placed
@@ -171,6 +171,24 @@ from each device are counted.  If the counter of a particular device exceeds
 the limit set here, no further I/O is sent to that device for the remainder of
 the respective operation. Setting the parameter to 0 disables the counters
 altogether.
+.IP
+\fBpv_min_size\fP \(em
+Minimal size (in KB) of the block device which can be used as a PV.
+In clustered environment all nodes have to use the same value.
+Any value smaller than 512KB is ignored.  Up to and include version 2.02.84
+the default was 512KB.  From 2.02.85 onwards it was changed to 2MB to
+avoid floppy drives by default.
+.IP
+\fBissue_discards\fP \(em
+Issue discards to a logical volumes's underlying physical volume(s) when the
+logical volume is no longer using the physical volumes' space (e.g. lvremove,
+lvreduce, etc).  Discards inform the storage that a region is no longer in use.
+Storage that supports discards advertise the protocol specific way discards
+should be issued by the kernel (TRIM, UNMAP, or WRITE SAME with UNMAP bit set).
+Not all storage will support or benefit from discards but SSDs and thinly
+provisioned LUNs generally do.  If set to 1, discards will only be issued if
+both the storage and kernel provide support.
+.IP
 .TP
 \fBallocation\fP \(em Space allocation policies
 .IP
@@ -182,9 +200,9 @@ segment of the existing LV.  If there is insufficient space and a
 list of tags is defined here, it will check whether any of them are
 attached to the PVs concerned and then seek to match those PV tags
 between existing extents and new extents.
-.IP 
+.IP
 The @ prefix for tags is required.
-Use the special tag "@*" as a wildcard to match any PV tag and so use 
+Use the special tag "@*" as a wildcard to match any PV tag and so use
 all PV tags for this purpose.
 .IP
 For example, LVs are mirrored between two sites within a single VG.
@@ -208,14 +226,20 @@ is invoked.  By default tools append messages to the log file.
 \fBverbose\fP \(em Default level (0-3) of messages sent to stdout or stderr.
 3 is the most verbose; 0 should produce the least output.
 .IP
+\fBsilent\fP \(em Set to 1 to suppress all non-essential tool output.
+When set, display and reporting tools will still write the requested
+device properties to standard output, but messages confirming that
+something was or wasn't changed will be reduced to the 'verbose' level
+and not appear unless -v is supplied.
+.IP
 \fBsyslog\fP \(em Set to 1 (the default) to send log messages through syslog.
 Turn off by setting to 0.  If you set to an integer greater than one,
-this is used - unvalidated - as the facility.  The default is LOG_USER.  
+this is used - unvalidated - as the facility.  The default is LOG_USER.
 See /usr/include/sys/syslog.h for safe facility values to use.
 For example, LOG_LOCAL0 might be 128.
 .IP
-\fBindent\fP \(em When set to 1 (the default) messages are indented 
-according to their severity, two spaces per level.  
+\fBindent\fP \(em When set to 1 (the default) messages are indented
+according to their severity, two spaces per level.
 Set to 0 to turn off indentation.
 .IP
 \fBcommand_names\fP \(em When set to 1, the command name is used as a
@@ -226,7 +250,7 @@ Default is 0 (off).
 Default is two spaces.
 .IP
 \fBactivation\fP \(em Set to 1 to log messages while
-devices are suspended during activation.  
+devices are suspended during activation.
 Only set this temporarily while debugging a problem because
 in low memory situations this setting can cause your machine to lock up.
 .TP
@@ -237,21 +261,21 @@ Backup copies of former metadata for each volume group are archived here.
 Defaults to "#DEFAULT_ARCHIVE_DIR#".
 .IP
 \fBbackup_dir\fP \(em Directory used for automatic metadata backups.
-A single backup copy of the current metadata for each volume group 
+A single backup copy of the current metadata for each volume group
 is stored here.
 Defaults to "#DEFAULT_BACKUP_DIR#".
 .IP
 \fBarchive\fP \(em Whether or not tools automatically archive existing
 metadata into \fBarchive_dir\fP before making changes to it.
-Default is 1 (automatic archives enabled).  
-Set to 0 to disable.  
-Disabling this might make metadata recovery difficult or impossible 
+Default is 1 (automatic archives enabled).
+Set to 0 to disable.
+Disabling this might make metadata recovery difficult or impossible
 if something goes wrong.
 .IP
-\fBbackup\fP \(em Whether or not tools make an automatic backup 
-into \fBbackup_dir\fP after changing metadata.  
+\fBbackup\fP \(em Whether or not tools make an automatic backup
+into \fBbackup_dir\fP after changing metadata.
 Default is 1 (automatic backups enabled).  Set to 0 to disable.
-Disabling this might make metadata recovery difficult or impossible 
+Disabling this might make metadata recovery difficult or impossible
 if something goes wrong.
 .IP
 \fBretain_min\fP \(em Minimum number of archives to keep.
@@ -279,23 +303,23 @@ Defaults to /proc.
 .IP
 \fBumask\fP \(em File creation mask for any files and directories created.
 Interpreted as octal if the first digit is zero.
-Defaults to 077.  
+Defaults to 077.
 Use 022 to allow other users to read the files by default.
 .IP
 \fBformat\fP \(em The default value of \fB--metadatatype\fP used
-to determine which format of metadata to use when creating new 
+to determine which format of metadata to use when creating new
 physical volumes and volume groups. \fBlvm1\fP or \fBlvm2\fP.
 .IP
-\fBfallback_to_lvm1\fP \(em Set this to 1 if you need to 
+\fBfallback_to_lvm1\fP \(em Set this to 1 if you need to
 be able to switch between 2.4 kernels using LVM1 and kernels
 including device-mapper.
 The LVM2 tools should be installed as normal and
 the LVM1 tools should be installed with a .lvm1 suffix e.g.
-vgscan.lvm1.  
+vgscan.lvm1.
 If an LVM2 tool is then run but unable to communicate
-with device-mapper, it will automatically invoke the equivalent LVM1 
-version of the tool.  Note that for LVM1 tools to 
-manipulate physical volumes and volume groups created by LVM2 you 
+with device-mapper, it will automatically invoke the equivalent LVM1
+version of the tool.  Note that for LVM1 tools to
+manipulate physical volumes and volume groups created by LVM2 you
 must use \fB--metadataformat lvm1\fP when creating them.
 .IP
 \fBlibrary_dir\fP \(em A directory searched for LVM2's shared libraries
@@ -312,7 +336,7 @@ avoid conflicting LVM2 commands running concurrently on a single
 machine. 0 disables locking and risks corrupting your metadata.
 If set to 2, the tools will load the external \fBlocking_library\fP
 (see below).
-If the tools were configured \fB--with-cluster=internal\fP 
+If the tools were configured \fB--with-cluster=internal\fP
 (the default) then 3 means to use built-in cluster-wide locking.
 Type 4 enforces read-only metadata and forbids any operations that
 might want to modify Volume Group metadata.
@@ -337,11 +361,11 @@ such a library, look at the lib/locking source code directory.
 Setting this to 0 does nothing, neither creating nor destroying any tag.
 The machine name used is the nodename as returned by \fBuname\fP (2).
 .IP
-Additional host tags to be set can be listed here as subsections. 
+Additional host tags to be set can be listed here as subsections.
 The @ prefix for tags is optional.
-Each of these host tag subsections can contain a \fBhost_list\fP 
-array of host names. If any one of these entries matches the machine 
-name exactly then the host tag gets defined on this particular host, 
+Each of these host tag subsections can contain a \fBhost_list\fP
+array of host names. If any one of these entries matches the machine
+name exactly then the host tag gets defined on this particular host,
 otherwise it doesn't.
 .IP
 After lvm.conf has been processed, LVM2 works through each host
@@ -360,9 +384,9 @@ tags { tag1 { } tag2 { host_list = [ "fs1", "fs2" ] } }
 .IP
 These options are useful if you are replicating configuration files
 around a cluster.  Use of \fBhosttags = 1\fP means every machine
-can have static and identical local configuration files yet use 
+can have static and identical local configuration files yet use
 different settings and activate different logical volumes by
-default.  See also \fBvolume_list\fP below and \fB--addtag\fP 
+default.  See also \fBvolume_list\fP below and \fB--addtag\fP
 in \fBlvm\fP (8).
 .TP
 \fBactivation\fP \(em Settings affecting device-mapper activation
@@ -381,13 +405,13 @@ returns zeros, see \fBlvcreate\fP (8).
 \fBmirror_region_size\fP \(em Unit size in KB for copy operations
 when mirroring.
 .IP
-\fBreadahead\fP \(em Used when there is no readahead value stored 
+\fBreadahead\fP \(em Used when there is no readahead value stored
 in the volume group metadata.  Set to \fBnone\fP to disable
 readahead in these circumstances or \fBauto\fP to use the default
 value chosen by the kernel.
 .IP
-\fBreserved_memory\fP, \fBreserved_stack\fP \(em How many KB to reserve 
-for LVM2 to use while logical volumes are suspended.  If insufficient 
+\fBreserved_memory\fP, \fBreserved_stack\fP \(em How many KB to reserve
+for LVM2 to use while logical volumes are suspended.  If insufficient
 memory is reserved before suspension, there is a risk of machine deadlock.
 .IP
 \fBprocess_priority\fP \(em The nice value to use while devices are
@@ -399,19 +423,42 @@ logical volumes getting queued) for the shortest possible time.
 all requests to activate a logical volume on this machine
 are passed.  A logical volume is only activated if it matches
 an item in the list.  Tags must be preceded by @ and are checked
-against all tags defined in the logical volume and volume group 
+against all tags defined in the logical volume and volume group
 metadata for a match.
 @* is short-hand to check every tag set on the host machine (see
 \fBtags\fP above).
 Logical volume and volume groups can also be included in the list
 by name e.g. vg00, vg00/lvol1.
+.IP
+\fBauto_activation_volume_list\fP \(em This acts as a filter through
+which all requests to autoactivate a logical volume on this machine
+are passed. A logical volume is autoactivated if it matches
+an item in the list. Volumes must also pass the \fBvolume_list\fP
+filter, if present. Tags must be preceded by @ and are checked against
+all tags defined in the logical volume and volume group metadata for
+a match. @* is short-hand to check every tag set on the host machine
+(see \fBtags\fP above).
+Logical volume and volume groups can also be included in the list
+by name e.g. vg00, vg00/lvol1.
+.IP
+\fBread_only_volume_list\fP \(em This acts as a filter through
+which all requests to activate a logical volume on this machine
+are passed.  A logical volume is activated in read-only mode (instead
+of read-write) if it matches an item in the list.  Volumes must first
+pass the \fBvolume_list\fP filter, if present.  Tags must be preceded
+by @ and are checked against all tags defined in the logical volume
+and volume group metadata for a match.
+@* is short-hand to check every tag set on the host machine (see
+\fBtags\fP above).
+Logical volume and volume groups can also be included in the list
+by name e.g. vg00, vg00/lvol1.
 .TP
 \fBmetadata\fP \(em Advanced metadata settings
 .IP
 \fBpvmetadatacopies\fP \(em When creating a physical volume using the
 LVM2 metadata format, this is the default number of copies of metadata
-to store on each physical volume.  
-Currently it can be set to 0, 1 or 2.  The default is 1.  
+to store on each physical volume.
+Currently it can be set to 0, 1 or 2.  The default is 1.
 If set to 2, one copy is placed at the beginning of the disk
 and the other is placed at the end.
 It can be overridden on the command line with \fB--pvmetadatacopies\fP
@@ -420,7 +467,7 @@ If creating a volume group with just one physical volume, it's a
 good idea to have 2 copies.  If creating a large volume group with
 many physical volumes, you may decide that 3 copies of the metadata
 is sufficient, i.e. setting it to 1 on three of the physical volumes,
-and 0 on the rest.  Every volume group must contain at least one 
+and 0 on the rest.  Every volume group must contain at least one
 physical volume with at least 1 copy of the metadata (unless using
 the text files described below).  The disadvantage of having lots
 of copies is that every time the tools access the volume group, every
@@ -429,7 +476,7 @@ tools.
 .IP
 \fBpvmetadatasize\fP \(em Approximate number of sectors to set aside
 for each copy of the metadata. Volume groups with large numbers of
-physical or logical volumes, or volumes groups containing complex 
+physical or logical volumes, or volumes groups containing complex
 logical volume structures will need additional space for their metadata.
 The metadata areas are treated as circular buffers, so
 unused space becomes filled with an archive of the most recent
@@ -477,16 +524,20 @@ and with no other on-disk metadata, \fBpvmetadatacopies = 0\fP.
 Alternatively these directories can be in addition to the
 on-disk metadata areas.  This feature was created during the
 development of the LVM2 metadata before the new on-disk metadata
-areas were designed and no longer gets tested.  
-It is not supported under low-memory conditions, and it is 
-important never to edit these metadata files unless you fully 
-understand how things work: to make changes you should always use 
+areas were designed and no longer gets tested.
+It is not supported under low-memory conditions, and it is
+important never to edit these metadata files unless you fully
+understand how things work: to make changes you should always use
 the tools as normal, or else vgcfgbackup, edit backup, vgcfgrestore.
 .SH FILES
 .I #DEFAULT_SYS_DIR#/lvm.conf
+.br
 .I #DEFAULT_ARCHIVE_DIR#
+.br
 .I #DEFAULT_BACKUP_DIR#
+.br
 .I #DEFAULT_CACHE_DIR#/.cache
+.br
 .I #DEFAULT_LOCK_DIR#
 .SH SEE ALSO
 .BR lvm (8),
index 7c7c85a2e4e7b97a4bd5e2a5c3f4a0bb8a1aea75..0d588137c33b7db65b6784b68a62f86d1c5efd27 100644 (file)
@@ -5,6 +5,6 @@ lvmchange \- change attributes of the logical volume manager
 .B lvmchange
 .SH DESCRIPTION
 lvmchange is not currently supported under LVM2, although
-\fBdmsetup (8)\fP has a \fBremove_all\fP command.
+\fBdmsetup\fP(8) has a \fBremove_all\fP command.
 .SH SEE ALSO
 .BR dmsetup (8)
index fb3d61074d84922570c77a9b1238b789a6d8aae4..0722e22e92a72077ac05c71d2991e69183e4196b 100644 (file)
@@ -6,15 +6,18 @@
 
 .SH "SYNOPSIS"
 .B lvmconf
-[\-\-disable-cluster]
-[\-\-enable-cluster]
-[\-\-file <configfile>]
-[\-\-lockinglib <lib>]
-[\-\-lockinglibdir <dir>]
+.RB [ \-\-disable-cluster ]
+.RB [ \-\-enable-cluster ]
+.RB [ \-\-file
+.RI < configfile >]
+.RB [ \-\-lockinglib
+.RI < lib >]
+.RB [ \-\-lockinglibdir
+.RI < dir >]
 
 .SH "DESCRIPTION"
-.B lvmconf
-is a script that modifies the locking configuration in an lvm configuration file. See \fBlvm.conf\fP(5).
+lvmconf is a script that modifies the locking configuration in
+an lvm configuration file. See \fBlvm.conf\fP(5).
 
 .SH "OPTIONS"
 .TP
@@ -24,13 +27,14 @@ Set \fBlocking_type\fR to the default non-clustered type.
 .BR \-\-enable-cluster
 Set \fBlocking_type\fR to the default clustered type on this system.
 .TP
-.BR \-\-file " " \fI<configfile>\fR
-Apply the changes to \fBconfigfile\fR instead of the default \fB#DEFAULT_SYS_DIR#/lvm.conf\fR.
+.BR \-\-file " <" \fIconfigfile >
+Apply the changes to \fIconfigfile\fP instead of the default
+\fI#DEFAULT_SYS_DIR#/lvm.conf\fP.
 .TP
-.BR \-\-lockinglib " " \fI<lib>\fR
+.BR \-\-lockinglib " <" \fIlib >
 Set external \fBlocking_library\fR locking library to load if an external locking type is used.
 .TP
-.BR \-\-lockinglibdir " " \fI<dir>\fR
+.BR \-\-lockinglibdir " <" \fIdir >
 .SH FILES
 .I #DEFAULT_SYS_DIR#/lvm.conf
 
index da4188b791efe898edfe348f5772b310389ab687..7b3e08ba19fc7649703a528a013fb0d5f4cfce98 100644 (file)
@@ -3,22 +3,23 @@
 lvmdiskscan \- scan for all devices visible to LVM2
 .SH SYNOPSIS
 .B lvmdiskscan
-[\-d|\-\-debug] [\-h|\-?|\-\-help] 
-[\-l|\-\-lvmpartition]
-[\-v|\-\-verbose]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-l | \-\-lvmpartition ]
+.RB [ \-v | \-\-verbose ]
 .SH DESCRIPTION
-\fBlvmdiskscan\fP scans all SCSI, (E)IDE disks, multiple devices and a bunch
+lvmdiskscan scans all SCSI, (E)IDE disks, multiple devices and a bunch
 of other block devices in the system looking for LVM physical volumes.
 The size reported is the real device size.
-Define a filter in \fBlvm.conf\fP(5) to restrict 
+Define a filter in \fBlvm.conf\fP(5) to restrict
 the scan to avoid a CD ROM, for example.
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .TP
-.I \-l, \-\-lvmpartition
+.BR \-l ", " \-\-lvmpartition
 Only reports Physical Volumes.
 .SH SEE ALSO
-.BR lvm (8), 
+.BR lvm (8),
 .BR lvm.conf (5),
 .BR pvscan (8),
 .BR vgscan (8)
index 9cce137c82ebad29e7e3820ce124b46fc1343843..3d53420563cf87fc89c4ed888c0b8ba07a7ebc55 100644 (file)
@@ -2,9 +2,17 @@
 .SH NAME
 lvmdump - create lvm2 information dumps for diagnostic purposes
 .SH SYNOPSIS
-\fBlvmdump\fP [options] [-d directory]
+.B lvmdump
+.RB [ \-a ]
+.RB [ \-c ]
+.RB [ \-d
+.IR directory ]
+.RB [ \-h ]
+.RB [ \-m ]
 .SH DESCRIPTION
-\fBlvmdump\fP is a tool to dump various information concerning LVM2. By default, it creates a tarball suitable for submission along with a problem report.
+lvmdump is a tool to dump various information concerning LVM2.
+By default, it creates a tarball suitable for submission along
+with a problem report.
 .PP
 The content of the tarball is as follows:
 .br
@@ -22,33 +30,45 @@ The content of the tarball is as follows:
 .br
 - list of files present /sys/devices/virtual/block
 .br
-- if enabled with -m, metadata dump will be also included
+- if enabled with \-m, metadata dump will be also included
 .br
-- if enabled with -a, debug output of vgscan, pvscan and list of all available volume groups, physical volumes and logical volumes will be included
+- if enabled with \-a, debug output of vgscan, pvscan and list of all available volume groups, physical volumes and logical volumes will be included
 .br
-- if enabled with -c, cluster status info
+- if enabled with \-c, cluster status info
 .SH OPTIONS
 .TP
-\fB\-h\fR \(em print help message
+.B \-a
+Advanced collection.
+\fBWARNING\fR: if lvm is already hung, then this script may hang as well
+if \fB\-a\fR is used.
 .TP
-\fB\-a\fR \(em advanced collection 
-\fBWARNING\fR: if lvm is already hung, then this script may hang as well if \fB\-a\fR is used
+.B \-c
+If clvmd is running, gather cluster data as well.
 .TP
-\fB\-m\fR \(em gather LVM metadata from the PVs
-This option generates a 1:1 dump of the metadata area from all PVs visible to the system, which can cause the dump to increase in size considerably. However, the metadata dump may represent a valuable diagnostic resource.
+.B \-d  \fIdirectory
+Dump into a directory instead of tarball
+By default, lvmdump will produce a single compressed tarball containing
+all the information. Using this option, it can be instructed to only
+produce the raw dump tree, rooted in \fIdirectory\fP.
 .TP
-\fB\-d\fR directory \(em dump into a directory instead of tarball
-By default, lvmdump will produce a single compressed tarball containing all the information. Using this option, it can be instructed to only produce the raw dump tree, rooted in \fBdirectory\fP.
+.B \-h
+Print help message
 .TP
-\fB\-c\fR \(em if clvmd is running, gather cluster data as well
+.B \-m
+Gather LVM metadata from the PVs
+This option generates a 1:1 dump of the metadata area from all PVs visible
+to the system, which can cause the dump to increase in size considerably.
+However, the metadata dump may represent a valuable diagnostic resource.
 .SH ENVIRONMENT VARIABLES
 .TP
-\fBLVM_BINARY\fP 
+\fBLVM_BINARY\fP
 The LVM2 binary to use.
 Defaults to "lvm".
 Sometimes you might need to set this to "/sbin/lvm.static", for example.
 .TP
-\fBDMSETUP_BINARY\fP 
+\fBDMSETUP_BINARY\fP
 The dmsetup binary to use.
 Defaults to "dmsetup".
 .PP
+.SH SEE ALSO
+.BR lvm (8)
diff --git a/man/lvmetad.8.in b/man/lvmetad.8.in
new file mode 100644 (file)
index 0000000..ef1096d
--- /dev/null
@@ -0,0 +1,51 @@
+.TH LVMETAD 8 "LVM TOOLS #VERSION#" "Red Hat Inc" \" -*- nroff -*-
+.SH NAME
+lvmetad \- LVM metadata cache daemon
+.SH SYNOPSIS
+.B lvmetad
+.RB [ \-l
+.RI {all|wire|debug}
+.RB ]
+.RB [ \-s
+.RI path
+.RB ]
+.RB [ \-f ]
+.RB [ \-h ]
+.RB [ \-V ]
+.RB [ \-? ]
+.SH DESCRIPTION
+lvmetad is a metadata caching daemon for LVM. The daemon receives notifications
+from udev rules (which must be installed for LVM to work correctly when lvmetad
+is in use). Through these notifications, lvmetad has an up-to-date and
+consistent image of the volume groups available in the system.
+
+By default, lvmetad, even if running, is not used by LVM. See \fBlvm.conf\fP(5).
+.SH OPTIONS
+.TP
+.BR \-l " {" \fIall | \fIwire | \fIdebug }
+Select the type of log messages to generate.
+Messages are logged by syslog.  
+Additionally, when -f is given they are also sent to standard error.
+Since release 2.02.98, there are two classes of messages: wire and debug.
+Selecting 'all' supplies both and is equivalent to a comma-separated list
+-l wire,debug.
+Prior to release 2.02.98, repeating -d from 1 to 3 times, viz. -d, -dd, -ddd,
+increased the detail of messages.
+.TP
+.B \-f
+Don't fork, run in the foreground.
+.TP
+.BR \-h ", " \-?
+Show help information.
+.TP
+.B \-s \fIpath
+Path to the socket file to use. The option overrides both the built-in default
+(#DEFAULT_RUN_DIR#/lvmetad.socket) and the environment variable
+LVM_LVMETAD_SOCKET.
+.TP
+.B \-V
+Show version of dmeventd.
+
+.SH SEE ALSO
+.BR lvm (8),
+.BR lvm.conf (5)
index b78ba6edef8f138694432677936f1a0fdab1e90c..e0af210cc4c79b9c59a16c5bd9e2f26bc7803a05 100644 (file)
@@ -7,8 +7,7 @@ lvmsadc \- LVM system activity data collector
 .B lvmsadc
 
 .SH "DESCRIPTION"
-.B lvmsadc
-is not currently supported under LVM2.
+lvmsadc is not currently supported under LVM2.
 
 .SH "SEE ALSO"
 .BR lvm (8)
index 091954540676012b8a09f543817c58f4f3da97fd..29de791849dc11751798cbb2e2028d5651732e2a 100644 (file)
@@ -7,8 +7,7 @@ lvmsar \- LVM system activity reporter
 .B lvmsar
 
 .SH "DESCRIPTION"
-.B lvmsar
-is not currently supported under LVM2.
+lvmsar is not currently supported under LVM2.
 
 .SH "SEE ALSO"
 .BR lvm (8)
index fc7722332bff0e50f39d85645608034b99f7d66f..dabdc880152d113eb4b499aa3b70743d9f65493f 100644 (file)
@@ -3,87 +3,97 @@
 lvreduce \- reduce the size of a logical volume
 .SH SYNOPSIS
 .B lvreduce
-[\-A|\-\-autobackup y|n] [\-d|\-\-debug] [\-f|\-\-force]
-[\-h|\-?|\-\-help]
-[\-\-noudevsync]
-{\-l|\-\-extents [\-]LogicalExtentsNumber[%{VG|LV|FREE|ORIGIN}] |
-\-L|\-\-size [\-]LogicalVolumeSize[bBsSkKmMgGtTpPeE]}
-[\-n|\-\-nofsck]
-[\-r|\-\-resizefs]
-[\-t|\-\-test]
-[\-v|\-\-verbose] LogicalVolume[Path]
+.RB [ \-A | \-\-autobackup
+.RI { y | n }]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-\-help ]
+.RB [ \-t | \-\-test ]
+.RB [ \-v | \-\-verbose ]
+.RB [ \-\-version ]
+.RB [ \-f | \-\-force ]
+.RB [ \-\-noudevsync ]
+.RB { \-l | \-\-extents
+.RI [ \- ] LogicalExtentsNumber [ % { VG | LV | FREE | ORIGIN "}] |"
+.RB [ \-L | \-\-size
+.RI [ \- ] LogicalVolumeSize [ bBsSkKmMgGtTpPeE ]}
+.RB [ \-n | \-\-nofsck ]
+.RB [ \-r | \-\-resizefs ]
+.IR LogicalVolume { Name | Path }
 .SH DESCRIPTION
 lvreduce allows you to reduce the size of a logical volume.
 Be careful when reducing a logical volume's size, because data in the
-reduced part is lost!!! 
-.br 
-You should therefore ensure that any filesystem on the volume is 
+reduced part is lost!!!
+.br
+You should therefore ensure that any filesystem on the volume is
 resized
 .I before
 running lvreduce so that the extents that are to be removed are not in use.
 .br
 Shrinking snapshot logical volumes (see
-.B lvcreate(8)
+.BR lvcreate (8)
 for information to create snapshots) is supported as well.
 But to change the number of copies in a mirrored logical
-volume use 
-.B lvconvert (8).
+volume use
+.BR lvconvert (8).
 .br
 Sizes will be rounded if necessary - for example, the volume size must
 be an exact number of extents and the size of a striped segment must
 be a multiple of the number of stripes.
 .br
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .TP
-.I \-f, \-\-force
+.BR \-f ", " \-\-force
 Force size reduction without prompting even when it may cause data loss.
 .TP
-.I \-\-noudevsync
-Disable udev synchronisation. The
-process will not wait for notification from udev.
-It will continue irrespective of any possible udev processing
-in the background.  You should only use this if udev is not running
-or has rules that ignore the devices LVM2 creates.
-.TP
-.I \-l, \-\-extents [\-]LogicalExtentsNumber[%{VG|LV|FREE|ORIGIN}]
+.IR \fB\-l ", " \fB\-\-extents " [" \- ] LogicalExtentsNumber [ % { VG | LV | FREE | ORIGIN }]
 Reduce or set the logical volume size in units of logical extents.
-With the - sign the value will be subtracted from
+With the \fI-\fP sign the value will be subtracted from
 the logical volume's actual size and without it the value will be taken
 as an absolute size.
 The number can also be expressed as a percentage of the total space
-in the Volume Group with the suffix %VG, relative to the existing
-size of the Logical Volume with the suffix %LV, as a percentage of the
-remaining free space in the Volume Group with the suffix %FREE, or (for
+in the Volume Group with the suffix \fI%VG\fP, relative to the existing
+size of the Logical Volume with the suffix \fI%LV\fP, as a percentage of the
+remaining free space in the Volume Group with the suffix \fI%FREE\fP, or (for
 a snapshot) as a percentage of the total space in the Origin Logical
-Volume with the suffix %ORIGIN.
+Volume with the suffix \fI%ORIGIN\fP.
+The resulting value for the substraction is rounded downward, for the absolute
+size it is rounded upward.
 .TP
-.I \-L, \-\-size [\-]LogicalVolumeSize[bBsSkKmMgGtTpPeE]
+.IR \fB\-L ", " \fB\-\-size " [" \- ] LogicalVolumeSize [ bBsSkKmMgGtTpPeE ]
 Reduce or set the logical volume size in units of megabytes.
-A size suffix of k for kilobyte, m for megabyte, 
-g for gigabytes, t for terabytes, p for petabytes 
-or e for exabytes is optional.
-With the - sign the value will be subtracted from
+A size suffix of \fIk\fP for kilobyte, \fIm\fP for megabyte,
+\fIg\fP for gigabytes, \fIt\fP for terabytes, \fIp\fP for petabytes
+or \fIe\fP for exabytes is optional.
+With the \fI\-\fP sign the value will be subtracted from
 the logical volume's actual size and without it it will be taken as
 an absolute size.
 .TP
-.I \-n, \-\-nofsck
+.BR \-n ", " \-\-nofsck
 Do not perform fsck before resizing filesystem when filesystem
-requires it. You may need to use \fB--force\fR to proceed with 
+requires it. You may need to use \fB\-\-force\fR to proceed with
 this option.
 .TP
-.I \-r, \-\-resizefs
-Resize underlying filesystem together with the logical volume using 
-\fBfsadm\fR(8).
-.SH Example
-"lvreduce -l -3 vg00/lvol1" reduces the size of logical volume lvol1
-in volume group vg00 by 3 logical extents.
+.BR \-\-noudevsync
+Disable udev synchronisation. The
+process will not wait for notification from udev.
+It will continue irrespective of any possible udev processing
+in the background.  You should only use this if udev is not running
+or has rules that ignore the devices LVM2 creates.
+.TP
+.BR \-r ", " \-\-resizefs
+Resize underlying filesystem together with the logical volume using
+.BR fsadm (8).
+.SH Examples
+Reduce the size of logical volume lvol1 in volume group vg00 by 3 logical extents:
+.sp
+.B lvreduce \-l \-3 vg00/lvol1
 .SH SEE ALSO
 .BR fsadm (8),
 .BR lvchange (8),
-.BR lvconvert (8), 
-.BR lvcreate (8), 
-.BR lvextend (8), 
-.BR lvm (8), 
+.BR lvconvert (8),
+.BR lvcreate (8),
+.BR lvextend (8),
+.BR lvm (8),
 .BR lvresize (8),
 .BR vgreduce (8)
index ac39cb43493e8180c4e619b6fd3895edf0f89d16..1d48a11b5c6f8563c9a8982eb0c301edc33afa6d 100644 (file)
@@ -3,13 +3,19 @@
 lvremove \- remove a logical volume
 .SH SYNOPSIS
 .B lvremove
-[\-A|\-\-autobackup y|n] [\-d|\-\-debug] [\-f|\-\-force]
-[\-h|\-?|\-\-help] 
-[\-\-noudevsync]
-[\-t|\-\-test]
-[\-v|\-\-verbose] LogicalVolumePath [LogicalVolumePath...]
+.RB [ \-A | \-\-autobackup
+.RI { y | n }]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-\-help ]
+.RB [ \-t | \-\-test ]
+.RB [ \-v | \-\-verbose ]
+.RB [ \-\-version ]
+.RB [ \-f | \-\-force ]
+.RB [ \-\-noudevsync ]
+.IR LogicalVolume { Name |  Path }
+.RI [ LogicalVolume { Name | Path }...]
 .SH DESCRIPTION
-\fBlvremove\fP removes one or more logical volumes.
+lvremove removes one or more logical volumes.
 Confirmation will be requested before deactivating any active logical
 volume prior to removal.  Logical volumes cannot be deactivated
 or removed while they are open (e.g. if they contain a mounted filesystem).
@@ -21,29 +27,29 @@ issued from one node can do this.
 .SH OPTIONS
 See \fBlvm\fP(8) for common options.
 .TP
-.I \-f, \-\-force
+.BR \-f ", " \-\-force
 Remove active logical volumes without confirmation.
 .TP
-.I \-\-noudevsync
+.B \-\-noudevsync
 Disable udev synchronisation. The
 process will not wait for notification from udev.
 It will continue irrespective of any possible udev processing
 in the background.  You should only use this if udev is not running
 or has rules that ignore the devices LVM2 creates.
-.SH EXAMPLES
-Remove the active logical volume lvol1 in volume group vg00 
+.SH Examples
+Remove the active logical volume lvol1 in volume group vg00
 without asking for confirmation:
 .sp
-\      \fBlvremove -f vg00/lvol1\fP
+.B lvremove \-f vg00/lvol1
 .sp
 Remove all logical volumes in volume group vg00:
 .sp
-\      \fBlvremove vg00\fP
+.B lvremove vg00
 .SH SEE ALSO
-.BR lvcreate (8), 
+.BR lvcreate (8),
 .BR lvdisplay (8),
-.BR lvchange (8),  
-.BR lvm (8), 
+.BR lvchange (8),
+.BR lvm (8),
 .BR lvs (8),
 .BR lvscan (8),
 .BR vgremove (8)
index 8f9007241cb832f75eabbecc443af9af528bffa7..ea640aed4ee370e7d3cc4772c9058dbbf175a73b 100644 (file)
@@ -3,26 +3,26 @@
 lvrename \- rename a logical volume
 .SH SYNOPSIS
 .B lvrename
-.RB [ \-A | \-\-autobackup " {" y | n }]
+.RB [ \-A | \-\-autobackup
+.RI { y | n }]
 .RB [ \-d | \-\-debug ]
-.RB [ \-f | \-\-force ]
 .RB [ \-h | \-\-help ]
-.RB [ \-\-noudevsync ]
 .RB [ \-t | \-\-test ]
 .RB [ \-v | \-\-verbose ]
 .RB [ \-\-version ]
-.TP
-.IR "OldLogicalVolumePath NewLogicalVolume" { Path | Name }
-.TP
-.I VolumeGroupName OldLogicalVolumeName NewLogicalVolumeName
+.RB [ \-f | \-\-force ]
+.RB [ \-\-noudevsync ]
+.RI { OldLogicalVolume { Name | Path }
+.IR NewLogicalVolume { Name | Path }
+|
+.I VolumeGroupName OldLogicalVolumeName NewLogicalVolumeName\fR}
 .SH DESCRIPTION
-.B lvrename
-renames an existing logical volume from
+lvrename renames an existing logical volume from
 .IR OldLogicalVolume { Name | Path }
 to
 .IR NewLogicalVolume { Name | Path }.
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .TP
 .BR \-\-noudevsync
 Disable udev synchronisation. The
@@ -31,23 +31,14 @@ It will continue irrespective of any possible udev processing
 in the background.  You should only use this if udev is not running
 or has rules that ignore the devices LVM2 creates.
 .SH EXAMPLE
-To rename
-.B lvold
-in volume group
-.B vg02
-to
-.BR lvnew :
-.nf
-
-\      lvrename /dev/vg02/lvold /dev/vg02/lvnew
-
-.fi
-An alternate syntax to rename this logical volume is
-.nf
-
-\      lvrename vg02 lvold lvnew
-
-.fi
+To rename lvold in volume group vg02 to lvnew:
+.sp
+.B lvrename /dev/vg02/lvold vg02/lvnew
+.sp
+An alternate syntax to rename this logical volume is:
+.sp
+.B lvrename vg02 lvold lvnew
+.sp
 .SH SEE ALSO
 .BR lvm (8), 
 .BR lvchange (8),
index 677b2db3e60d77d83f0e43151bdf899d3fdb7c3e..7e859932b3ef9fc7480779c45cdc0b2cf3734a42 100644 (file)
@@ -3,17 +3,19 @@
 lvresize \- resize a logical volume
 .SH SYNOPSIS
 .B lvresize
-[\-\-alloc AllocationPolicy]
-[\-A|\-\-autobackup y|n] [\-d|\-\-debug] [\-h|\-?|\-\-help]
-[\-\-noudevsync]
-[\-i|\-\-stripes Stripes [\-I|\-\-stripesize StripeSize]]
-{\-l|\-\-extents [+]LogicalExtentsNumber[%{VG|LV|PVS|FREE|ORIGIN}] |
-\-L|\-\-size [+]LogicalVolumeSize[bBsSkKmMgGtTpPeE]}
-[\-f|\-\-force]
-[\-n|\-\-nofsck]
-[\-r|\-\-resizefs]
-[\-t|\-\-test]
-[\-v|\-\-verbose] LogicalVolumePath [PhysicalVolumePath[:PE[-PE]]...]
+.RB [ \-\-alloc " " \fIAllocationPolicy ]
+.RB [ \-\-noudevsync ]
+.RB [ \-i | \-\-stripes " " \fIStripes
+.RB [ \-I | \-\-stripesize " " \fIStripeSize ]]
+.RB {[ \-l | \-\-extents
+.RI [ + | \- ] LogicalExtentsNumber [ % { VG | LV | PVS | FREE | ORIGIN "}] |"
+.RB [ \-L | \-\-size
+.RI [ + | \- ] LogicalVolumeSize [ bBsSkKmMgGtTpPeE ]}
+.RB [ \-f | \-\-force ]
+.RB [ \-n | \-\-nofsck ]
+.RB [ \-r | \-\-resizefs ]
+.IR LogicalVolume { Name | Path }
+.RI [ PhysicalVolumePath [ :PE [ -PE ]]...]
 .SH DESCRIPTION
 lvresize allows you to resize a logical volume.
 Be careful when reducing a logical volume's size, because data in the reduced
@@ -21,74 +23,76 @@ part is lost!!!
 You should therefore ensure that any filesystem on the volume is
 shrunk first so that the extents that are to be removed are not in use.
 Resizing snapshot logical volumes (see
-.B lvcreate(8)
+.BR lvcreate (8)
 for information about creating snapshots) is supported as well.
 But to change the number of copies in a mirrored logical
 volume use 
 .BR lvconvert (8).
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .TP
-.I \-f, \-\-force
+.BR \-f ", " \-\-force
 Force resize without prompting even when it may cause data loss.
 .TP
-.I \-l, \-\-extents [+|-]LogicalExtentsNumber[%{VG|LV|PVS|FREE|ORIGIN}]
-Change or set the logical volume size in units of logical extents.
-With the + or - sign the value is added to or subtracted from the actual size
-of the logical volume and without it, the value is taken as an absolute one.
-The number can also be expressed as a percentage of the total space
-in the Volume Group with the suffix %VG, relative to the existing
-size of the Logical Volume with the suffix %LV, as a percentage of
-the remaining free space of the PhysicalVolumes on the command line with the
-suffix %PVS, as a percentage of the remaining free space in the
-Volume Group with the suffix %FREE, or (for a snapshot) as a percentage
-of the total space in the Origin Logical Volume with the suffix %ORIGIN.
-.TP
-.I \-n, \-\-nofsck
+.BR \-n ", " \-\-nofsck
 Do not perform fsck before resizing filesystem when filesystem
 requires it. You may need to use \fB--force\fR to proceed with 
 this option.
 .TP
-.I \-\-noudevsync
-Disable udev synchronisation. The
-process will not wait for notification from udev.
-It will continue irrespective of any possible udev processing
-in the background.  You should only use this if udev is not running
-or has rules that ignore the devices LVM2 creates.
-.TP
-.I \-r, \-\-resizefs
+.BR \-r ", " \-\-resizefs
 Resize underlying filesystem together with the logical volume using 
 \fBfsadm\fR(8).
 .TP
-.I \-L, \-\-size [+|-]LogicalVolumeSize[bBsSkKmMgGtTpPeE]
+.IR \fB\-l ", " \fB\-\-extents " [" + | - ] LogicalExtentsNumber [ % { VG | LV | PVS | FREE | ORIGIN }]
+Change or set the logical volume size in units of logical extents.
+With the \fI+\fP or \fI-\fP sign the value is added to or subtracted from the actual size
+of the logical volume and without it, the value is taken as an absolute one.
+The number can also be expressed as a percentage of the total space
+in the Volume Group with the suffix \fI%VG\fP, relative to the existing
+size of the Logical Volume with the suffix \fI%LV\fP, as a percentage of
+the remaining free space of the PhysicalVolumes on the command line with the
+suffix \fI%PVS\fP, as a percentage of the remaining free space in the
+Volume Group with the suffix \fI%FREE\fP, or (for a snapshot) as a percentage
+of the total space in the Origin Logical Volume with the suffix \fI%ORIGIN\fP.
+The resulting value is rounded downward for the substraction otherwise
+it is rounded upward.
+.TP
+.IR \fB\-L ", " \fB\-\-size " [" + | - ] LogicalVolumeSize [ bBsSkKmMgGtTpPeE ]
 Change or set the logical volume size in units of megabytes.
-A size suffix of M for megabytes,
-G for gigabytes, T for terabytes, P for petabytes 
-or E for exabytes is optional.
-With the + or - sign the value is added to or subtracted from
-the actual size of the logical volume and without it, the value is taken as an
-absolute one.
+A size suffix of \fIM\fP for megabytes,
+\fIG\fP for gigabytes, \fIT\fP for terabytes, \fIP\fP for petabytes
+or \fIE\fP for exabytes is optional.
+With the \fI+\fP or \fI-\fP sign the value is added or subtracted
+from the actual size of the logical volume and rounded
+to the full extent size and without it,
+the value is taken as an absolute one.
 .TP
-.I \-i, \-\-stripes Stripes
+.BR \-i ", " \-\-stripes " " \fIStripes
 Gives the number of stripes to use when extending a Logical Volume.
 Defaults to whatever the last segment of the Logical Volume uses.
 Not applicable to LVs using the original metadata LVM format, which must
 use a single value throughout.
 .TP
-.I \-I, \-\-stripesize StripeSize
+.BR \-I ", " \-\-stripesize " " \fIStripeSize
 Gives the number of kilobytes for the granularity of the stripes.
 Defaults to whatever the last segment of the Logical Volume uses.
 Not applicable to LVs using the original metadata LVM format, which
 must use a single value throughout.
 .br
-StripeSize must be 2^n (n = 2 to 9)
-.SH Examples
-.br
-"lvresize -L+16M vg1/lv1 /dev/sda:0-1 /dev/sdb:0-1"
+StripeSize must be 2^n (n = 2 to 9).
+.TP
+.B \-\-noudevsync
+Disable udev synchronisation. The
+process will not wait for notification from udev.
+It will continue irrespective of any possible udev processing
+in the background.  You should only use this if udev is not running
+or has rules that ignore the devices LVM2 creates.
+.SH EXAMPLES
 .br
-tries to extend a logical volume "vg1/lv1" by 16MB using physical extents
-/dev/sda:0-1 and /dev/sdb:0-1 for allocation of extents.
-
+Extend a logical volume vg1/lv1 by 16MB using physical extents
+/dev/sda:0-1 and /dev/sdb:0-1 for allocation of extents:
+.sp
+.B lvresize -L+16M vg1/lv1 /dev/sda:0-1 /dev/sdb:0-1
 .SH SEE ALSO
 .BR fsadm (8),
 .BR lvm (8), 
index baa14ab49b6bb045df066107767c00805d88709a..f31256cc370a446e4407a57501288041f4e2037e 100644 (file)
 lvs \- report information about logical volumes
 .SH SYNOPSIS
 .B lvs
-[\-a|\-\-all]
-[\-\-aligned] [\-d|\-\-debug] [\-h|\-?|\-\-help]
-[\-\-ignorelockingfailure] [\-\-nameprefixes] [\-\-noheadings] [\-\-nosuffix]
-[\-o|\-\-options [+]Field[,Field]]
-[\-O|\-\-sort [+|-]Key1[,[+|-]Key2[,...]]]
-[\-P|\-\-partial] [\-\-rows] [\-\-segments]
-[\-\-separator Separator]
-[\-\-unbuffered]
-[\-\-units hHbBsSkKmMgGtTpPeE]
-[\-\-unquoted]
-[\-v|\-\-verbose] 
-[\-\-version] [VolumeGroupName [VolumeGroupName...]]
+.RB [ \-\-aligned ]
+.RB [ \-a | \-\-all ]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-\-ignorelockingfailure ]
+.RB [ \-\-nameprefixes ]
+.RB [ \-\-noheadings ]
+.RB [ \-\-nosuffix ]
+.RB [ \-o | \-\-options
+.RI [ + ] Field [, Field ]]
+.RB [ \-O | \-\-sort
+.RI [ + | \- ] Key1 [,[ + | \- ] Key2 [,...]]]
+.RB [ \-P | \-\-partial ]
+.RB [ \-\-rows ]
+.RB [ \-\-separator
+.IR Separator ]
+.RB [ \-\-segments ]
+.RB [ \-\-unbuffered ]
+.RB [ \-\-units
+.IR hHbBsSkKmMgGtTpPeE ]
+.RB [ \-\-unquoted ]
+.RB [ \-v | \-\-verbose ]
+.RB [ \-\-version ]
+.RI [ VolumeGroupName
+.RI [ VolumeGroupName ...]]
+
 .SH DESCRIPTION
 lvs produces formatted output about logical volumes.
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See
+.BR lvm (8)
+for common options.
 .TP
-.I \-\-all
+.B \-\-aligned
+Use with \fB\-\-separator\fP to align the output columns.
+.TP
+.B \-\-all
 Include information in the output about internal Logical Volumes that
 are components of normally-accessible Logical Volumes, such as mirrors,
 but which are not independently accessible (e.g. not mountable).
 The names of such Logical Volumes are enclosed within square brackets
-in the output.  For example, after creating a mirror using 'lvcreate -m1
---mirrorlog disk', this option will reveal three internal Logical
+in the output.  For example, after creating a mirror using
+.B lvcreate -m1 --mirrorlog disk
+, this option will reveal three internal Logical
 Volumes, with suffixes mimage_0, mimage_1, and mlog.
 .TP
-.I \-\-aligned
-Use with \-\-separator to align the output columns.
-.TP
-.I \-\-nameprefixes
+.B \-\-nameprefixes
 Add an "LVM2_" prefix plus the field name to the output.  Useful
-with --noheadings to produce a list of field=value pairs that can
-be used to set environment variables (for example, in \fBudev (7)\fP rules).
+with \fB\-\-noheadings\fP to produce a list of field=value pairs that can
+be used to set environment variables (for example, in
+.BR udev (7)
+rules).
 .TP
-.I \-\-noheadings
+.B \-\-noheadings
 Suppress the headings line that is normally the first line of output.
 Useful if grepping the output.
 .TP
-.I \-\-nosuffix
-Suppress the suffix on output sizes.  Use with \-\-units (except h and H)
-if processing the output.
+.B \-\-nosuffix
+Suppress the suffix on output sizes.  Use with \fB\-\-units\fP
+(except h and H) if processing the output.
 .TP
-.I \-o, \-\-options
-Comma-separated ordered list of columns.  Precede the list with '+' to append
-to the default selection of columns instead of replacing it.
+.BR \-o ", " \-\-options
+Comma-separated ordered list of columns.  Precede the list with '\fI+\fP'
+to append to the default selection of columns instead of replacing it.
 .IP
-Use \fb-o lv_all\fP to select all logical volume columns, and \fb-o seg_all\fP
+Use \fB\-o lv_all\fP to select all logical volume columns,
+and \fB\-o seg_all\fP
 to select all logical volume segment columns.
 .IP
-Use \fb-o help\fP to view the full list of columns available.
+Use \fB\-o help\fP to view the full list of columns available.
 .IP
 Column names include:
-lv_uuid, lv_name, lv_path, lv_attr, lv_major, lv_minor, lv_read_ahead, lv_kernel_major,
-lv_kernel_minor, lv_kernel_read_ahead, lv_size, seg_count, origin, origin_size,
-snap_percent, copy_percent, move_pv, convert_lv, lv_tags, mirror_log, modules,
-segtype, stripes, stripesize, regionsize, chunksize, seg_start, seg_start_pe,
-seg_size, seg_tags, seg_pe_ranges, devices.
+chunk_size,
+convert_lv,
+copy_percent,
+data_lv,
+devices,
+discards,
+lv_attr,
+lv_host,
+lv_kernel_major,
+lv_kernel_minor,
+lv_kernel_read_ahead,
+lv_major,
+lv_minor,
+lv_name,
+lv_path,
+lv_read_ahead,
+lv_size,
+lv_tags,
+lv_time,
+lv_uuid,
+metadata_lv,
+mirror_log,
+modules,
+move_pv,
+origin,
+origin_size,
+pool_lv,
+region_size,
+segtype,
+seg_count,
+seg_pe_ranges,
+seg_size,
+seg_start,
+seg_start_pe,
+seg_tags,
+snap_percent,
+stripes,
+stripe_size,
+thin_count,
+transaction_id,
+zero.
 .IP
-With \-\-segments, any "seg_" prefixes are optional; otherwise any "lv_"
-prefixes are optional.  Columns mentioned in \fBvgs (8)\fP 
+With \fB\-\-segments\fP, any "seg_" prefixes are optional;
+otherwise any "lv_" prefixes are optional. Columns mentioned in
+.BR vgs (8)
 can also be chosen.
 .IP
-The lv_attr bits are: 
+The lv_attr bits are:
 .RS
 .IP 1 3
 Volume type: (m)irrored, (M)irrored without initial sync, (o)rigin,
-(O)rigin with merging snapshot, (s)napshot, merging (S)napshot, (p)vmove,
-(v)irtual, mirror (i)mage, mirror (I)mage out-of-sync, under (c)onversion
+(O)rigin with merging snapshot, (r)aid, (R)aid without initial sync,
+(s)napshot, merging (S)napshot, (p)vmove, (v)irtual,
+mirror or raid (i)mage, mirror or raid (I)mage out-of-sync, mirror (l)og device,
+under (c)onversion, thin (V)olume, (t)hin pool, (T)hin pool data, raid or
+thin pool m(e)tadata
 .IP 2 3
-Permissions: (w)riteable, (r)ead-only
+Permissions: (w)riteable, (r)ead-only, (R)ead-only activation of non-read-only
+volume
 .IP 3 3
-Allocation policy: (c)ontiguous, c(l)ing, (n)ormal, (a)nywhere, (i)nherited
+Allocation policy:  (a)nywhere, (c)ontiguous, (i)nherited, c(l)ing, (n)ormal
 This is capitalised if the volume is currently locked against allocation
-changes, for example during \fBpvmove\fP (8).
+changes, for example during
+.BR pvmove (8).
 .IP 4 3
 fixed (m)inor
 .IP 5 3
 State: (a)ctive, (s)uspended, (I)nvalid snapshot, invalid (S)uspended snapshot,
+snapshot (m)erge failed, suspended snapshot (M)erge failed,
 mapped (d)evice present without tables, mapped device present with (i)nactive table
 .IP 6 3
 device (o)pen
+.IP 7 3
+Target type: (m)irror, (r)aid, (s)napshot, (t)hin, (u)nknown, (v)irtual.
+This groups logical volumes related to the same kernel target together.  So,
+for example, mirror images, mirror logs as well as mirrors themselves appear as
+(m) if they use the original device-mapper mirror kernel driver; whereas the raid
+equivalents using the md raid kernel driver all appear as (r).
+Snapshots using the original device-mapper driver appear as (s); whereas
+snapshots of thin volumes using the new thin provisioning driver appear as (t).
+.IP 8 3
+Newly-allocated data blocks are overwritten with blocks of (z)eroes before use.
+.IP 9 3
+(p)artial: One or more of the Physical Volumes this Logical Volume uses is
+missing from the system.
 .RE
 .TP
-.I \-\-segments
-Use default columns that emphasize segment information.
-.TP
-.I \-O, \-\-sort
+.BR \-O ", " \-\-sort
 Comma-separated ordered list of columns to sort by.  Replaces the default
-selection. Precede any column with - for a reverse sort on that column.
+selection. Precede any column with '\fI\-\fP' for a reverse sort on that column.
 .TP
-.I \-\-rows
+.B \-\-rows
 Output columns as rows.
 .TP
-.I \-\-separator Separator
+.B \-\-segments
+Use default columns that emphasize segment information.
+.TP
+.B \-\-separator \fISeparator
 String to use to separate each column.  Useful if grepping the output.
 .TP
-.I \-\-unbuffered
+.B \-\-unbuffered
 Produce output immediately without sorting or aligning the columns properly.
 .TP
-.I \-\-units hHbBsSkKmMgGtTpPeE
+.B \-\-units \fIhHbBsSkKmMgGtTpPeE
 All sizes are output in these units: (h)uman-readable, (b)ytes, (s)ectors,
-(k)ilobytes, (m)egabytes, (g)igabytes, (t)erabytes, (p)etabytes, (e)xabytes.  
-Capitalise to use multiples of 1000 (S.I.) instead of 1024.  Can also specify 
-custom units e.g. \-\-units 3M
+(k)ilobytes, (m)egabytes, (g)igabytes, (t)erabytes, (p)etabytes, (e)xabytes.
+Capitalise to use multiples of 1000 (S.I.) instead of 1024.  Can also specify
+custom units e.g. \fB\-\-units 3M\fP
 .TP
-.I \-\-unquoted
-When used with --nameprefixes, output values in the field=value pairs are not quoted.
+.B \-\-unquoted
+When used with \fB\-\-nameprefixes\fP, output values in the field=value
+pairs are not quoted.
 .SH SEE ALSO
 .BR lvm (8),
 .BR lvdisplay (8),
index 3dbe9d8f03c6b05e9e21f1c186251ada28d0b4f5..5102691899d7c8d8638466ee1620c60c88ada089 100644 (file)
@@ -1,6 +1,6 @@
 .TH LVSCAN 8 "LVM TOOLS #VERSION#" "Sistina Software UK" \" -*- nroff -*-
 .SH NAME
-lvscan \- scan (all disks) for logical volumes
+lvscan \- scan (all disks) for Logical Volumes
 .SH SYNOPSIS
 .B lvscan
 .RB [ \-a | \-\-all]
@@ -11,24 +11,29 @@ lvscan \- scan (all disks) for logical volumes
 .RB [ \-P | \-\-partial ]
 .RB [ \-v | \-\-verbose ]
 .SH DESCRIPTION
-.B lvscan
-scans all known volume groups or all supported LVM block devices
-in the system for defined logical volumes.
+lvscan scans all known volume groups or all supported LVM block devices
+in the system for defined Logical Volumes.  The output consists
+of one line for each Logical Volume indicating whether or not it is active,
+a snapshot or origin, the size of the device and its allocation policy.
+Use \fBlvs\fP(8) or \fBlvdisplay\fP(8) to obtain more-comprehensive
+information about the Logical Volumes.
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .TP
 .BR \-\-all
 Include information in the output about internal Logical Volumes that
 are components of normally-accessible Logical Volumes, such as mirrors,
 but which are not independently accessible (e.g. not mountable).
-For example, after creating a mirror using 'lvcreate -m1 --mirrorlog disk',
+For example, after creating a mirror using
+.B lvcreate \-m1 \-\-mirrorlog disk\fR,
 this option will reveal three internal Logical Volumes, with suffixes
 mimage_0, mimage_1, and mlog.
 .TP
 .BR \-b ", " \-\-blockdevice
-Adds the device major and minor numbers to the display
-of each logical volume.
+This option is now ignored.  Instead, use \fBlvs\fP(8) or
+\fBlvdisplay\fP(8) to obtain the device number.
 .SH SEE ALSO
-.BR lvm (8), 
+.BR lvm (8),
 .BR lvcreate (8),
 .BR lvdisplay (8)
+.BR lvs (8)
index 1bf6a4ff4fef781031873c245ef03fedd4cf76af..5e6c15e9113992fdbd5c78704d27a074a637af02 100644 (file)
@@ -3,40 +3,51 @@
 pvchange \- change attributes of a physical volume
 .SH SYNOPSIS
 .B pvchange
-[\-\-addtag Tag]
-[\-A|\-\-autobackup y|n] [\-d|\-\-debug] 
-[\-f|\-\-force]
-[\-\-deltag Tag]
-[\-\-metadataignore y|n]
-[\-h|\-?|\-\-help]
-[\-t|\-\-test]
-[\-v|\-\-verbose] [\-a|\-\-all] [\-x|\-\-allocatable y|n]
-[\-u|\-\-uuid] [PhysicalVolumePath...]
+.RB [ \-\-addtag
+.IR Tag ]
+.RB [ \-A | \-\-autobackup
+.RI { y | n }]
+.RB [ \-d | \-\-debug ]
+.RB [ \-f | \-\-force ]
+.RB [ \-\-deltag
+.IR Tag ]
+.RB [ \-\-metadataignore
+.RI { y | n }]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-t | \-\-test ]
+.RB [ \-v | \-\-verbose ]
+.RB [ \-a | \-\-all ]
+.RB [ \-x | \-\-allocatable
+.RI { y | n }]
+.RB [ \-u | \-\-uuid ]
+.RI [ PhysicalVolumePath ...]
 .SH DESCRIPTION
 pvchange allows you to change the allocation permissions of one or
 more physical volumes.
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .TP
-.I \-a, \-\-all
+.BR \-a ", " \-\-all
 If PhysicalVolumePath is not specified on the command line all
 physical volumes are searched for and used.
 .TP
-.I \-\-metadataignore " y|n"
+.BR \-\-metadataignore " {" \fIy | \fIn }
 Ignore or un-ignore metadata areas on this physical volume.
 If metadata areas on a physical volume are ignored, LVM will
 not not store metadata in the metadata areas present on this Physical
 Volume.
 .TP
-.I \-u, \-\-uuid
+.BR \-u ", " \-\-uuid
 Generate new random UUID for specified physical volumes.
 .TP
-.I \-x, \-\-allocatable y|n
+.BR \-x ", " \-\-allocatable " {" \fIy | \fIn }
 Enable or disable allocation of physical extents on this physical volume.
 .SH Example
-"pvchange -x n /dev/sdk1" disallows the allocation of physical extents
-on this physical volume (possibly because of disk errors, or because it will
-be removed after freeing it.
+Disallows the allocation of physical extents on this physical volume
+(possibly because of disk errors, or because it will be removed after
+freeing it:
+.sp
+.B pvchange -x n /dev/sdk1
 .SH SEE ALSO
 .BR lvm (8),
 .BR pvcreate (8)
index de3dfacbc25a1bfd3b24b6478f0015e20549d388..e6019af99ce9a7b28672ac7d47c8e8141be4fe9b 100644 (file)
@@ -6,25 +6,27 @@ pvck \- check physical volume metadata
 .RB [ \-d | \-\-debug ]
 .RB [ \-h | \-\-help ]
 .RB [ \-v | \-\-verbose ]
-.RB [ \-\-labelsector ]
-.IR PhysicalVolume " [" PhysicalVolume ...]
+.RB [ \-\-labelsector
+.IR sector ]
+.I PhysicalVolume
+.RI [ PhysicalVolume ...]
 .SH DESCRIPTION
 pvck checks physical volume LVM metadata for consistency.
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .TP
-.BR \-\-labelsector " sector"
+.B \-\-labelsector \fIsector
 By default, 4 sectors of \fBPhysicalVolume\fP are scanned for an LVM label,
 starting at sector 0.  This parameter allows you to specify a different
 starting sector for the scan and is useful for recovery situations.  For
 example, suppose the partition table is corrupted or lost on /dev/sda,
-but you suspect there was an LVM partition at approximately 100 MB.  This
-area of the disk may be scanned by using the \fB--labelsector\fP parameter
+but you suspect there was an LVM partition at approximately 100 MiB.  This
+area of the disk may be scanned by using the \fB\-\-labelsector\fP parameter
 with a value of 204800 (100 * 1024 * 1024 / 512 = 204800):
 .sp
-.BI "pvck --labelsector 204800 /dev/sda"
+.B pvck \-\-labelsector 204800 /dev/sda
 .sp
-Note that a script can be used with \fB--labelsector\fP to automate the
+Note that a script can be used with \fB\-\-labelsector\fP to automate the
 process of finding LVM labels.
 .SH SEE ALSO
 .BR lvm (8),
index cb100494425618582ae8eb0385227f9fdb30f546..3fec8dc6e731326a45ed764b4984f824cc2c2156 100644 (file)
@@ -4,34 +4,46 @@ pvcreate \- initialize a disk or partition for use by LVM
 .SH SYNOPSIS
 .B pvcreate
 .RB [ \-d | \-\-debug ]
-.RB [ \-f [ f ]| \-\-force " [" \-\-force ]]
-.RB [ \-y | \-\-yes ]
 .RB [ \-h | \-\-help ]
 .RB [ \-t | \-\-test ]
 .RB [ \-v | \-\-verbose ]
+.RB [ \-\-version ]
+.RB [ \-f [ f ]| \-\-force
+.RB [ \-\-force ]]
+.RB [ \-y | \-\-yes ]
 .RB [ \-\-labelsector ]
-.RB [ \-M | \-\-metadatatype type ]
-.RB [ \-\-[pv]metadatacopies #copies ]
-.RB [ \-\-metadatasize size ]
-.RB [ \-\-metadataignore y|n ]
-.RB [ \-\-dataalignment alignment ]
-.RB [ \-\-dataalignmentoffset alignment_offset ]
-.RB [ \-\-restorefile file ]
+.RB [ \-M | \-\-metadatatype
+.IR type ]
+.RB [ \-\- [ pv ] metadatacopies
+.IR NumberOfCopies ]
+.RB [ \-\-metadatasize
+.IR size ]
+.RB [ \-\-metadataignore
+.RI { y | n }]
+.RB [ \-\-dataalignment
+.IR alignment ]
+.RB [ \-\-dataalignmentoffset
+.IR alignment_offset ]
+.RB [ \-\-restorefile
+.IR file ]
 .RB [ \-\-norestorefile ]
-.RB [ \-\-setphysicalvolumesize size ]
-.RB [ \-u | \-\-uuid uuid ]
-.RB [ \-\-version ]
-.RB [ \-Z | \-\-zero y|n ]
-.IR PhysicalVolume " [" PhysicalVolume ...]
+.RB [ \-\-setphysicalvolumesize
+.IR size ]
+.RB [ \-u | \-\-uuid
+.IR uuid ]
+.RB [ \-Z | \-\-zero
+.RI { y | n }]
+.I PhysicalVolume
+.RI [ PhysicalVolume ...]
 .SH DESCRIPTION
-.B pvcreate
-initializes
+pvcreate initializes
 .I PhysicalVolume
 for later use by the Logical Volume Manager (LVM).  Each
 .I PhysicalVolume
 can be a disk partition, whole disk, meta device, or loopback file.
 For DOS disk partitions, the partition id should be set to 0x8e using
-.BR fdisk "(8), " cfdisk "(8), "
+.BR fdisk (8),
+.BR cfdisk (8),
 or a equivalent.  For
 .B whole disk devices only
 the partition table must be erased, which will effectively destroy all
@@ -54,127 +66,127 @@ See \fBlvm\fP(8) for common options.
 .BR \-f ", " \-\-force
 Force the creation without any confirmation.  You can not recreate
 (reinitialize) a physical volume belonging to an existing volume group.
-In an emergency you can override this behaviour with -ff.
+In an emergency you can override this behaviour with \fB-ff\fP.
 .TP
-.BR \-u ", " \-\-uuid " uuid"
-Specify the uuid for the device.  
-Without this option, \fBpvcreate\fP generates a random uuid.
+.BR \-u ", " \-\-uuid " " \fIuuid
+Specify the uuid for the device.
+Without this option, \fBpvcreate\fP(8) generates a random uuid.
 All of your physical volumes must have unique uuids.
-You need to use this option before restoring a backup of LVM metadata 
+You need to use this option before restoring a backup of LVM metadata
 onto a replacement device - see \fBvgcfgrestore\fP(8).  As such, use of
-\fB--restorefile\fP is compulsory unless the \fB--norestorefile\fP is
+\fB\-\-restorefile\fP is compulsory unless the \fB\-\-norestorefile\fP is
 used.
 .TP
 .BR \-y ", " \-\-yes
 Answer yes to all questions.
 .TP
-.BR \-Z ", " \-\-zero " y|n"
-Whether or not the first 4 sectors (2048 bytes) of the device should be 
+.BR \-Z ", " \-\-zero " {" \fIy | \fIn }
+Whether or not the first 4 sectors (2048 bytes) of the device should be
 wiped.
-If this option is not given, the 
-default is to wipe these sectors unless either or both of the --restorefile 
-or --uuid options were specified.
+If this option is not given, the
+default is to wipe these sectors unless either or both of the
+\fB\-\-restorefile\fP or \fB\-\-uuid\fP options were specified.
 .SH NEW METADATA OPTIONS
 LVM2 introduces a new format for storing metadata on disk.
-This new format is more efficient and resilient than the format the 
-original version of LVM used and offers the advanced user greater 
+This new format is more efficient and resilient than the format the
+original version of LVM used and offers the advanced user greater
 flexibility and control.
-.sp
-The new format may be selected on the command line with \fB-M2\fP or by 
-setting \fBformat = "lvm2"\fP in the \fBglobal\fP section of \fBlvm.conf\fP.
+.P
+The new format may be selected on the command line with \fB\-M2\fP or by
+setting \fBformat = "lvm2"\fP in the \fBglobal\fP section of \fBlvm.conf\fP(5).
 Each physical volume in the same volume group must use the same format, but
-different volume groups on a machine may use different formats 
+different volume groups on a machine may use different formats
 simultaneously: the tools can handle both formats.
 Additional formats can be added as shared libraries.
-.sp
-Additional tools for manipulating the locations and sizes of metadata areas 
+.P
+Additional tools for manipulating the locations and sizes of metadata areas
 will be written in due course.  Use the verbose/debug options on the tools
 to see where the metadata areas are placed.
 .TP
-.BR \-\-metadatasize " size"
+.B \-\-metadatasize \fIsize
 The approximate amount of space to be set aside for each metadata area.
 (The size you specify may get rounded.)
 .TP
-.BR \-\-dataalignment " alignment"
+.B \-\-dataalignment \fIalignment
 Align the start of the data to a multiple of this number.
-You should also specify an appropriate \fBPhysicalExtentSize\fP when creating
+You should also specify an appropriate \fIPhysicalExtentSize\fP when creating
 the Volume Group with \fBvgcreate\fP.
 .sp
 To see the location of the first Physical Extent of an existing Physical Volume
 use \fBpvs -o +pe_start\fP .  It will be a multiple of the requested
-\fBalignment\fP.  In addition it may be shifted by \fBalignment_offset\fP from
-\fBdata_alignment_offset_detection\fP (if enabled in \fBlvm.conf\fP) or
-\fB--dataalignmentoffset\fP.
+alignment.  In addition it may be shifted by \fIalignment_offset\fP from
+\fIdata_alignment_offset_detection\fP (if enabled in \fBlvm.conf\fP(5)) or
+\fB\-\-dataalignmentoffset\fP.
 .TP
-.BR \-\-dataalignmentoffset " alignment_offset"
-Shift the start of the data area by this additional \fBalignment_offset\fP.
+.B \-\-dataalignmentoffset \fIalignment_offset
+Shift the start of the data area by this additional \fIalignment_offset\fP.
 .TP
-.BR \-\-[pv]metadatacopies " copies"
+.BR \-\- [ pv ] metadatacopies " " \fINumberOfCopies
 The number of metadata areas to set aside on each PV.  Currently
-this can be 0, 1 or 2.  
-If set to 2, two copies of the volume group metadata 
-are held on the PV, one at the front of the PV and one at the end.  
-If set to 1 (the default), one copy is kept at the front of the PV 
+this can be 0, 1 or 2.
+If set to 2, two copies of the volume group metadata
+are held on the PV, one at the front of the PV and one at the end.
+If set to 1 (the default), one copy is kept at the front of the PV
 (starting in the 5th sector).
 If set to 0, no copies are kept on this PV - you might wish to use this
 with VGs containing large numbers of PVs.  But if you do this and
-then later use \fBvgsplit\fP you must ensure that each VG is still going 
+then later use \fBvgsplit\fP(8) you must ensure that each VG is still going
 to have a suitable number of copies of the metadata after the split!
 .TP
-.BR \-\-metadataignore " y|n"
+.BR \-\-metadataignore " {" \fIy | \fIn }
 Ignore or un-ignore metadata areas on this physical volume.
 The default is "n".  This setting can be changed with \fBpvchange\fP.
 If metadata areas on a physical volume are ignored, LVM will
-not not store metadata in the metadata areas present on this Physical
+not store metadata in the metadata areas present on this Physical
 Volume.  Metadata areas cannot be created or extended after Logical
 Volumes have been allocated on the device. If you do not want to store
 metadata on this device, it is still wise always to allocate a metadata
 area in case you need it in the future and to use this option to instruct
 LVM2 to ignore it.
 .TP
-.BR \-\-restorefile " file"
+.B \-\-restorefile \fIfile
 In conjunction with \fB--uuid\fP, this extracts the location and size
 of the data on the PV from the file (produced by \fBvgcfgbackup\fP)
-and ensures that the metadata that the program produces is consistent 
-with the contents of the file i.e. the physical extents will be in 
+and ensures that the metadata that the program produces is consistent
+with the contents of the file i.e. the physical extents will be in
 the same place and not get overwritten by new metadata.  This provides
 a mechanism to upgrade the metadata format or to add/remove metadata
 areas. Use with care. See also \fBvgconvert\fP(8).
 .TP
-.BR \-\-norestorefile
-In conjunction with \fB--uuid\fP, this allows a uuid to be specified
+.B \-\-norestorefile
+In conjunction with \fB\-\-uuid\fP, this allows a \fIuuid\fP to be specified
 without also requiring that a backup of the metadata be provided.
 .TP
-.BR \-\-labelsector " sector"
-By default the PV is labelled with an LVM2 identifier in its second 
+.B \-\-labelsector \fIsector
+By default the PV is labelled with an LVM2 identifier in its second
 sector (sector 1).  This lets you use a different sector near the
 start of the disk (between 0 and 3 inclusive - see LABEL_SCAN_SECTORS
 in the source).  Use with care.
 .TP
-.BR \-\-setphysicalvolumesize " size"
+.B \-\-setphysicalvolumesize \fIsize
 Overrides the automatically-detected size of the PV.  Use with care.
-.SH EXAMPLES
+.SH Examples
 Initialize partition #4 on the third SCSI disk and the entire fifth
 SCSI disk for later use by LVM:
 .sp
 .B pvcreate /dev/sdc4 /dev/sde
-.sp
-If the 2nd SCSI disk is a 4KB sector drive that compensates for windows
-partitioning (sector 7 is the lowest aligned logical block, the 4KB
-sectors start at LBA -1, and consequently sector 63 is aligned on a 4KB
+
+If the 2nd SCSI disk is a 4KiB sector drive that compensates for windows
+partitioning (sector 7 is the lowest aligned logical block, the 4KiB
+sectors start at LBA -1, and consequently sector 63 is aligned on a 4KiB
 boundary) manually account for this when initializing for use by LVM:
 .sp
-.B pvcreate --dataalignmentoffset 7s /dev/sdb
-.sp
+.B pvcreate \-\-dataalignmentoffset 7s /dev/sdb
+
 .SH SEE ALSO
 .BR lvm.conf (5),
 .BR lvm (8),
-.BR vgcreate (8), 
-.BR vgextend (8), 
-.BR lvcreate (8), 
-.BR cfdisk (8), 
-.BR fdisk (8), 
-.BR losetup (8), 
-.BR mdadm (8), 
-.BR vgcfgrestore (8), 
+.BR vgcreate (8),
+.BR vgextend (8),
+.BR lvcreate (8),
+.BR cfdisk (8),
+.BR fdisk (8),
+.BR losetup (8),
+.BR mdadm (8),
+.BR vgcfgrestore (8),
 .BR vgconvert (8)
index efa3894e6ee89771479bd93063be8a69c7661d6f..342c45b90e38ae4d33fdc855123c3a2b49fa4b86 100644 (file)
@@ -3,48 +3,61 @@
 pvdisplay \- display attributes of a physical volume
 .SH SYNOPSIS
 .B pvdisplay
-[\-c|\-\-colon]
-[\-d|\-\-debug] [\-h|\-?|\-\-help]
-[\-\-ignorelockingfailure]
-[\-\-maps]
-[\-\-nosuffix]
-[\-s|\-\-short]
-[\-\-units hsbkmgtHKMGT]
-[\-v[v]|\-\-verbose [\-\-verbose]]
-[\-\-version]
-[PhysicalVolumePath [PhysicalVolumePath...]]
+.RB [ \-c | \-\-colon ]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-\-ignorelockingfailure ]
+.RB [ \-\-maps ]
+.RB [ \-\-nosuffix ]
+.RB [ \-s | \-\-short ]
+.RB [ \-\-units
+.IR hsbkmgtHKMGT ]
+.RB [ \-v [ v ]| \-\-verbose
+.RB [ \-\-verbose ]]
+.RB [ \-\-version ]
+.RI [ PhysicalVolumePath
+.RI [ PhysicalVolumePath ...]]
 .br
 
 .br
-.B pvdisplay \-\-columns | \-C
-[\-\-aligned]
-[\-a|\-\-all]
-[\-d|\-\-debug] [\-h|\-?|\-\-help]
-[\-\-ignorelockingfailure]
-[\-\-noheadings]
-[\-\-nosuffix]
-[\-o|\-\-options [+]Field[,Field]]
-[\-O|\-\-sort [+|-]Key1[,[+|-]Key2[,...]]]
-[\-\-separator Separator]
-[\-\-unbuffered]
-[\-\-units hHbBsSkKmMgGtTpPeE]
-[\-v[v]|\-\-verbose [\-\-verbose]]
-[\-\-version]
-[PhysicalVolumePath [PhysicalVolumePath...]]
+.B pvdisplay
+.BR \-\-columns | \-C
+.RB [ \-\-aligned ]
+.RB [ \-a | \-\-all ]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-\-ignorelockingfailure ]
+.RB [ \-\-noheadings ]
+.RB [ \-\-nosuffix ]
+.RB [ \-o | \-\-options
+.RI [ + ] Field [ ,Field ...]]
+.RB [ \-O | \-\-sort
+.RI [ + | \- ] Key1 [ , [ + | \- ] Key2 ...
+.RI ]]
+.RB [ \-\-separator
+.IR Separator ]
+.RB [ \-\-unbuffered ]
+.RB [ \-\-units
+.IR hHbBsSkKmMgGtTpPeE ]
+.RB [ \-v [ v ]| \-\-verbose
+.RB [ \-\-verbose ]]
+.RB [ \-\-version ]
+.RI [ PhysicalVolumePath
+.RI [ PhysicalVolumePath ...]]
 .SH DESCRIPTION
 pvdisplay allows you to see the attributes of one or more physical volumes
 like size, physical extent size, space used for the volume group descriptor
 area and so on.
 .P
-\fBpvs\fP (8) is an alternative that provides the same information 
-in the style of \fBps\fP (1).
+\fBpvs\fP(8) is an alternative that provides the same information 
+in the style of \fBps\fP(1).
 .SH OPTIONS
 See \fBlvm\fP for common options and \fBpvs\fP for options given with
 \fB\-\-columns\fP.
 .TP
-.I \-c, \-\-colon
+.BR \-c ", " \-\-colon
 Generate colon separated output for easier parsing in scripts or programs.
-N.B. \fBpvs\fP (8) provides considerably more control over the output.
+N.B. \fBpvs\fP(8) provides considerably more control over the output.
 .nf
 
 The values are:
@@ -63,16 +76,16 @@ The values are:
 
 .fi
 .TP
-.I \-s, \-\-short
+.BR \-s ", " \-\-short
 Only display the size of the given physical volumes.
 .TP
-.I \-m, \-\-maps
+.BR \-m ", " \-\-maps
 Display the mapping of physical extents to logical volumes and
 logical extents.
 .TP
-.I \-\-columns | \-C
-Display output in columns, the equivalent of \fBpvs\fP (8).  See
-\fBpvs (8)\fP for a description of other options with this form of
+.BR \-\-columns ", " \-C
+Display output in columns, the equivalent of \fBpvs\fP(8).  See
+\fBpvs\fP(8) for a description of other options with this form of
 \fBpvdisplay\fP.
 .SH SEE ALSO
 .BR lvm (8),
index 83db2316f37deab55815ceaca2ed7dcab5590f2c..de20abb6c11e662e4d09ad9c74cc6be48fd89e3c 100644 (file)
@@ -3,15 +3,22 @@
 pvmove \- move physical extents
 .SH SYNOPSIS
 .B pvmove
-[\-\-abort]
-[\-\-alloc AllocationPolicy]
-[\-b|\-\-background]
-[\-d|\-\-debug] [\-h|\-\-help] [\-i|\-\-interval Seconds]
-[\-\-noudevsync] [\-v|\-\-verbose] [\-n|\-\-name LogicalVolume]
-[SourcePhysicalVolume[:PE[-PE]...] [DestinationPhysicalVolume[:PE[-PE]...]...]]
+.RB [ \-\-abort ]
+.RB [ \-\-alloc
+.IR AllocationPolicy ]
+.RB [ \-b | \-\-background ]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-\-help ]
+.RB [ \-i | \-\-interval
+.IR Seconds ]
+.RB [ \-\-noudevsync ]
+.RB [ \-v | \-\-verbose ]
+.RB [ \-n | \-\-name
+.IR LogicalVolume ]
+.RI [ SourcePhysicalVolume [ :PE [ -PE ]...]
+.RI [ DestinationPhysicalVolume [ :PE [ -PE ]...]...]]
 .SH DESCRIPTION
-.B pvmove
-allows you to move the allocated physical extents (PEs) on
+pvmove allows you to move the allocated physical extents (PEs) on
 .I SourcePhysicalVolume
 to one or more other physical volumes (PVs).
 You can optionally specify a source
@@ -21,25 +28,25 @@ free (or specified) extents on
 .IR DestinationPhysicalVolume (s).
 If no
 .I DestinationPhysicalVolume
-is specifed, the normal allocation rules for the volume group are used.
+is specified, the normal allocation rules for the Volume Group are used.
 
-If \fBpvmove\fP gets interrupted for any reason (e.g. the machine crashes)
-then run \fBpvmove\fP again without any PhysicalVolume arguments to
+If pvmove gets interrupted for any reason (e.g. the machine crashes)
+then run pvmove again without any PhysicalVolume arguments to
 restart any moves that were in progress from the last checkpoint.
 Alternatively use \fBpvmove --abort\fP at any time to abort them
 at the last checkpoint.
 
 You can run more than one pvmove at once provided they are moving data
 off different SourcePhysicalVolumes, but additional pvmoves will ignore
-any logical volumes already in the process of being changed, so some
+any Logical Volumes already in the process of being changed, so some
 data might not get moved.
 
 \fBpvmove\fP works as follows:
 
-1. A temporary 'pvmove' logical volume is created to store
+1. A temporary 'pvmove' Logical Volume is created to store
 details of all the data movements required.
 
-2. Every logical volume in the volume group is searched
+2. Every Logical Volume in the Volume Group is searched
 for contiguous data that need moving
 according to the command line arguments.
 For each piece of data found, a new segment is added to the end of the
@@ -49,58 +56,97 @@ from the original location to a newly-allocated location.
 The original LV is updated to use the new temporary mirror segment
 in the pvmove LV instead of accessing the data directly.
 
-3. The volume group metadata is updated on disk.
+3. The Volume Group metadata is updated on disk.
 
-4. The first segment of the pvmove logical volume is activated and starts
+4. The first segment of the pvmove Logical Volume is activated and starts
 to mirror the first part of the data.  Only one segment is mirrored at once
 as this is usually more efficient.
 
 5. A daemon repeatedly checks progress at the specified time interval.
 When it detects that the first temporary mirror is in-sync,
 it breaks that mirror so that only the new location for that data gets used 
-and writes a checkpoint into the volume group metadata on disk.
+and writes a checkpoint into the Volume Group metadata on disk.
 Then it activates the mirror for the next segment of the pvmove LV.
 
 6. When there are no more segments left to be mirrored, 
-the temporary logical volume is removed and the volume group metadata 
-is updated so that the logical volumes reflect the new data locations.
+the temporary Logical Volume is removed and the Volume Group metadata 
+is updated so that the Logical Volumes reflect the new data locations.
 
 Note that this new process cannot support the original LVM1
 type of on-disk metadata.  Metadata can be converted using \fBvgconvert\fP(8).
 
+N.B. The moving of mirrors, snapshots and their origins is not yet supported.
+
 .SH OPTIONS
+See \fBlvm\fP(8) for common options.
 .TP
-.I \-\-abort
+.B \-\-abort
 Abort any moves in progress.
 .TP
-.I \-\-noudevsync
+.B \-\-noudevsync
 Disable udev synchronisation. The
 process will not wait for notification from udev.
 It will continue irrespective of any possible udev processing
 in the background.  You should only use this if udev is not running
 or has rules that ignore the devices LVM2 creates.
 .TP
-.I \-b, \-\-background
+.BR \-b ", " \-\-background
 Run the daemon in the background.
 .TP
-.I \-i, \-\-interval Seconds
+.BR \-i ", " \-\-interval " " \fISeconds
 Report progress as a percentage at regular intervals.
 .TP
-.I \-n, \-\-name " \fILogicalVolume\fR"
+.BR \-n ", " \-\-name " " \fILogicalVolume
 Move only the extents belonging to
 .I LogicalVolume
 from
 .I SourcePhysicalVolume
 instead of all allocated extents to the destination physical volume(s).
 
-.SH EXAMPLES
-To move all logical extents of any logical volumes on
-.B /dev/hda4
-to free physical extents elsewhere in the volume group, giving verbose
-runtime information, use:
+.SH Examples
+To move all Physical Extents that are used by simple Logical Volumes on
+/dev/sdb1 to free Physical Extents elsewhere in the Volume Group use:
+.sp
+.B pvmove /dev/sdb1
+.P
+Any mirrors, snapshots and their origins are left unchanged.
+.P
+Additionally, a specific destination device /dev/sdc1
+can be specified like this:
+.sp
+.B pvmove /dev/sdb1 /dev/sdc1
+.P
+To perform the action only on extents belonging to the single Logical Volume 
+lvol1 do this:
+.sp
+.B pvmove -n lvol1 /dev/sdb1 /dev/sdc1
+.P
+Rather than moving the contents of the entire device, it is possible to
+move a range of Physical Extents - for example numbers 1000 to 1999
+inclusive on /dev/sdb1 - like this:
+.sp
+.B pvmove /dev/sdb1:1000-1999
+.P
+To move a range of Physical Extents to a specific location (which must have
+sufficent free extents) use the form:
+.sp
+.B pvmove /dev/sdb1:1000-1999 /dev/sdc1
+.sp
+or
+.sp
+.B pvmove /dev/sdb1:1000-1999 /dev/sdc1:0-999
+.P
+If the source and destination are on the same disk, the 
+.B anywhere
+allocation policy would be needed, like this:
 .sp
-\      pvmove -v /dev/hda4
+.B pvmove --alloc anywhere /dev/sdb1:1000-1999 /dev/sdb1:0-999
+.P
+The part of a specific Logical Volume present within in a range of Physical
+Extents can also be picked out and moved, like this:
 .sp
+.B pvmove -n lvol1 /dev/sdb1:1000-1999 /dev/sdc1
 .SH SEE ALSO
 .BR lvm (8),
 .BR vgconvert (8)
+.BR pvs (8)
index b435fc7037c2186f63c780321936e40a7d9e32f2..5029228dfbf6f98f5cf2005219b68e581ac0e203 100644 (file)
@@ -3,20 +3,31 @@
 pvremove \- remove a physical volume
 .SH SYNOPSIS
 .B pvremove
-.RB [ \-d | \-\-debug]
-.RB [ \-f [ f ]| \-\-force " [" \-\-force ]]
-.RB [\-h | \-\-help]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-\-help ]
 .RB [ \-t | \-\-test ]
-.RB [ \-v [ v ]| \-\-verbose " [" \-\-verbose ]]
+.RB [ \-v | \-\-verbose ]
+.RB [ \-\-version ]
+.RB [ \-f [ f ]| \-\-force 
+.RB [ \-\-force ]]
 .RB [ \-y | \-\-yes ]
-.IR PhysicalVolume " [" PhysicalVolume ...]
+.I PhysicalVolume
+.RI [ PhysicalVolume ...]
 .SH DESCRIPTION
-.B pvremove
-wipes the label on a device so that LVM will no longer recognise it
-as a physical volume.
+pvremove wipes the label on a device so that LVM will no longer
+recognise it as a physical volume.
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
+.TP
+.BR \-ff ", " \-\-force " " \-\-force
+Force the removal of a physical volume belonging to an existing volume group.
+Normally \fBvgreduce\fP(8) should be used instead of this command.
+You cannot remove a physical volume which in use by some active logical volume.
+.TP
+.BR \-y ", " \-\-yes
+Answer yes to all questions.
 .SH SEE ALSO
 .BR lvm (8),
 .BR pvcreate (8),
-.BR pvdisplay (8)
+.BR pvdisplay (8),
+.BR vgreduce (8)
index 845f6d3c7f47c1c651cc0c7140ad53289213a81e..59539b8693508ca696c6f10ea3688d625a2bf5aa 100644 (file)
@@ -7,18 +7,20 @@ pvresize \- resize a disk or partition in use by LVM2
 .RB [ \-h | \-\-help ]
 .RB [ \-t | \-\-test ]
 .RB [ \-v | \-\-verbose ]
-.RB [ \-\-setphysicalvolumesize size ]
-.IR PhysicalVolume " [" PhysicalVolume ...]
+.RB [ \-\-version ]
+.RB [ \-\-setphysicalvolumesize
+.IR size ]
+.I PhysicalVolume 
+.RI [ PhysicalVolume ...]
 .SH DESCRIPTION
-.B pvresize
-resizes
+pvresize resizes
 .I PhysicalVolume
 which may already be in a volume group and have active logical volumes
 allocated on it.
 .SH OPTIONS
 See \fBlvm\fP(8) for common options.
 .TP
-.BR \-\-setphysicalvolumesize " size"
+.BI \-\-setphysicalvolumesize " size"
 Overrides the automatically-detected size of the PV.  Use with care, or
 prior to reducing the physical size of the device.
 .SH EXAMPLES
@@ -30,11 +32,10 @@ Shrink the PV on /dev/sda1 prior to shrinking the partition with fdisk
 (ensure that the PV size is appropriate for your intended new partition
 size):
 .sp
-.B pvresize --setphysicalvolumesize 40G /dev/sda1
+.B pvresize \-\-setphysicalvolumesize 40G /dev/sda1
 .sp
 .SH RESTRICTIONS
-.B pvresize
-will refuse to shrink
+pvresize will refuse to shrink
 .I PhysicalVolume
 if it has allocated extents after where its new end would be. In the future,
 it should relocate these elsewhere in the volume group if there is sufficient
@@ -46,4 +47,7 @@ does.
 won't currently work correctly on LVM1 volumes or PVs with extra
 metadata areas.
 .SH SEE ALSO
-.BR lvm "(8), " pvmove "(8), " lvresize "(8), " fdisk "(8)"
+.BR lvm (8),
+.BR pvmove (8),
+.BR lvresize (8),
+.BR fdisk (8)
index a5e1382cc326f617a9a821607399addebd024e63..4bdfa12de8427855ef5a4b0f467393b95141ae9f 100644 (file)
 pvs \- report information about physical volumes
 .SH SYNOPSIS
 .B pvs
-[\-a|\-\-all]
-[\-\-aligned] [\-d|\-\-debug] [\-h|\-?|\-\-help]
-[\-\-ignorelockingfailure] [\-\-nameprefixes] [\-\-noheadings] [\-\-nosuffix]
-[\-o|\-\-options [+]Field[,Field]]
-[\-O|\-\-sort [+|-]Key1[,[+|-]Key2[,...]]]
-[\-P|\-\-partial]
-[\-\-rows]
-[\-\-segments]
-[\-\-separator Separator]
-[\-\-unbuffered]
-[\-\-units hHbBsSkKmMgGtTpPeE]
-[\-\-unquoted]
-[\-v|\-\-verbose] 
-[\-\-version] [PhysicalVolume [PhysicalVolume...]]
+.RB [ \-a | \-\-all ]
+.RB [ \-\-aligned ]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-\-ignorelockingfailure ]
+.RB [ \-\-nameprefixes ]
+.RB [ \-\-noheadings ]
+.RB [ \-\-nosuffix ]
+.RB [ \-o | \-\-options
+.RI [ + ] Field [ ,Field ...]]
+.RB [ \-O | \-\-sort
+.RI [ + | \- ] Key1 [ , [ + | \- ] Key2 ...]]
+.RB [ \-P | \-\-partial ]
+.RB [ \-\-rows ]
+.RB [ \-\-segments ]
+.RB [ \-\-separator
+.IR Separator ]
+.RB [ \-\-unbuffered ]
+.RB [ \-\-units
+.IR hHbBsSkKmMgGtTpPeE ]
+.RB [ \-\-unquoted ]
+.RB [ \-v|\-\-verbose ]
+.RB [ \-\-version]
+.RI [ PhysicalVolume
+.RI [ PhysicalVolume ...]]
 .SH DESCRIPTION
 pvs produces formatted output about physical volumes.
 .SH OPTIONS
-See \fBlvm\fP for common options.
-\fB\-\-columns\fP.
+See \fBlvm\fP(8) for common options.
 .TP
-.I \-\-all
+.B \-\-all
 Include information in the output about devices that have not been
-initialized with \fBpvcreate\fP.
+initialized with \fBpvcreate\fP(8).
 .TP
-.I \-\-aligned
-Use with \-\-separator to align the output columns.
+.B \-\-aligned
+Use with \fB\-\-separator\fP to align the output columns.
 .TP
-.I \-\-nameprefixes
+.B \-\-nameprefixes
 Add an "LVM2_" prefix plus the field name to the output.  Useful
-with --noheadings to produce a list of field=value pairs that can
-be used to set environment variables (for example, in \fBudev (7)\fP rules).
+with \fB\-\-noheadings\fP to produce a list of field=value pairs that can
+be used to set environment variables (for example, in \fBudev\fP(7) rules).
 .TP
-.I \-\-noheadings
+.B \-\-noheadings
 Suppress the headings line that is normally the first line of output.
 Useful if grepping the output.
 .TP
-.I \-\-nosuffix
-Suppress the suffix on output sizes.  Use with \-\-units (except h and H)
-if processing the output.
+.B \-\-nosuffix
+Suppress the suffix on output sizes.  Use with \fB\-\-units\fP
+(except h and H) if processing the output.
 .TP
-.I \-o, \-\-options
-Comma-separated ordered list of columns.  Precede the list with '+' to append
-to the default selection of columns.
+.BR \-o ", " \-\-options
+Comma-separated ordered list of columns.  Precede the list with '\fI+\fP'
+to append to the default selection of columns.
 .IP
-Use \fb-o pv_all\fP to select all physical volume columns, and \fb-o pvseg_all\fP
-to select all Physical Volume segment columns.
+Use \fB-o pv_all\fP to select all physical volume columns,
+and \fB-o pvseg_all\fP to select all Physical Volume segment columns.
 .IP
-Use \fb-o help\fP to view the full list of columns available.
+Use \fB-o help\fP to view the full list of columns available.
 .IP
 Column names include: pv_fmt, pv_uuid, dev_size, pv_name, pv_mda_free,
 pv_mda_size, pe_start, pv_size, pv_free, pv_used, pv_attr, pv_pe_count,
 pv_pe_alloc_count, pv_tags, pv_mda_count, pv_mda_used_count,
 pvseg_start, and pvseg_size.
 .IP
-With --segments, any "pvseg_" prefixes are optional; otherwise any
-"pv_" prefixes are optional.  Columns mentioned in \fBvgs (8)\fP can also
-be chosen. The pv_attr bits are: (a)llocatable and e(x)ported.
+With \fB\-\-segments\fP, any "pvseg_" prefixes are optional; otherwise any
+"pv_" prefixes are optional.  Columns mentioned in \fBvgs\fP(8) can also
+be chosen. The pv_attr bits are: (a)llocatable, e(x)ported and (m)issing.
 .TP
-.I \-\-segments
+.B \-\-segments
 Produces one line of output for each contiguous allocation of space on each
 Physical Volume, showing the start (pvseg_start) and length (pvseg_size) in
 units of physical extents.
 .TP
-.I \-O, \-\-sort
+.BR \-O ", " \-\-sort
 Comma-separated ordered list of columns to sort by.  Replaces the default
-selection. Precede any column with - for a reverse sort on that column.
+selection. Precede any column with '\fI\-\fP' for a reverse sort on that
+column.
 .TP
-.I \-\-rows
+.B \-\-rows
 Output columns as rows.
 .TP
-.I \-\-separator Separator
+.B \-\-separator \fISeparator
 String to use to separate each column.  Useful if grepping the output.
 .TP
-.I \-\-unbuffered
+.B \-\-unbuffered
 Produce output immediately without sorting or aligning the columns properly.
 .TP
-.I \-\-units hHbBsSkKmMgGtTpPeE
+.B \-\-units \fIhHbBsSkKmMgGtTpPeE
 All sizes are output in these units: (h)uman-readable, (b)ytes, (s)ectors,
-(k)ilobytes, (m)egabytes, (g)igabytes, (t)erabytes, (p)etabytes, (e)xabytes.  
-Capitalise to use multiples of 1000 (S.I.) instead of 1024.  Can also specify 
+(k)ilobytes, (m)egabytes, (g)igabytes, (t)erabytes, (p)etabytes, (e)xabytes.
+Capitalise to use multiples of 1000 (S.I.) instead of 1024.  Can also specify
 custom units e.g. \-\-units 3M
 .TP
-.I \-\-unquoted
-When used with --nameprefixes, output values in the field=value pairs are not quoted.
+.B \-\-unquoted
+When used with \fB\-\-nameprefixes\fP, output values in the field=value
+pairs are not quoted.
 .SH SEE ALSO
 .BR lvm (8),
 .BR pvdisplay (8),
index 4a6bcd742ea7d06fa495e2c0f0f95dccb71b985e..1be3109dd13fd0955fc5e5e6e5bb0dd1ba34a9b9 100644 (file)
@@ -3,19 +3,33 @@
 pvscan \- scan all disks for physical volumes
 .SH SYNOPSIS
 .B pvscan
-.RB [ \-d | \-\-debug]
-.RB [\-e | \-\-exported]
-.RB [\-h | \-\-help]
-.RB [\-\-ignorelockingfailure]
-.RB [ \-n | \-\-novolumegroup]
-.RB [\-s | \-\-short]
-.RB [\-u | \-\-uuid]
-.RB [ \-v [ v ]| \-\-verbose " [" \-\-verbose ]]
-.SH DESCRIPTION
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-\-help ]
+.RB [ \-v | \-\-verbose ]
+.RB [ \-\-version ]
+.RB [ \-\-ignorelockingfailure ]
+.RB [ \-e | \-\-exported ]
+.RB [ \-n | \-\-novolumegroup ]
+.RB [ \-s | \-\-short ]
+.RB [ \-u | \-\-uuid ]
+.BR
+
 .B pvscan
-scans all supported LVM block devices in the system for physical volumes.
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-\-help ]
+.B \-\-cache
+.RB [ \-a | \-\-activate " " \fIay ]
+.RB [ \-\-major
+.I major
+.B \-\-minor
+.I minor
+|
+.IR DevicePath ]...
+.SH DESCRIPTION
+pvscan scans all supported LVM block devices in the system for
+physical volumes.
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .TP
 .BR \-e ", " \-\-exported
 Only show physical volumes belonging to exported volume groups.
@@ -28,6 +42,19 @@ Short listing format.
 .TP
 .BR \-u ", " \-\-uuid
 Show UUIDs (Uniform Unique Identifiers) in addition to device special names.
+.TP
+.BR \-a ", " \-\-activate " " \fIay
+Together with the information already cached in lvmetad, automatically activate
+any logical volumes that become activatable after the scan done on one or more devices.
+The logical volume to autoactivate is matched against the
+activation/auto_activation_volume_list set in lvm.conf. Autoactivation is not yet
+supported on logical volumes that are part of partial or clustered volume groups.
+.TP
+.BR \-\-cache " [" \-\-major " " \fImajor " " \-\-minor " " \fIminor " | " \fIDevicePath " ]..."
+Scan one or more devices and instruct the lvmetad daemon to update its cached
+state accordingly.  Called internally by udev rules.
+All devices listed explicitly are processed \fBregardless\fP of any device
+filters set in lvm.conf.
 .SH SEE ALSO
 .BR lvm (8),
 .BR pvcreate (8),
index 1a72a015eb34ae2fa7474add34bbc6a80abd4681..ce8db8b3ee489d4002749a08e8d28f1043383b03 100644 (file)
@@ -4,29 +4,28 @@ vgcfgbackup \- backup volume group descriptor area
 .SH SYNOPSIS
 .B vgcfgbackup
 .RB [ \-d | \-\-debug ]
-.RB [ \-f | \-\-file " filename" ]
+.RB [ \-f | \-\-file
+.RI < filename >]
 .RB [ \-h | \-\-help ]
 .RB [ \-\-ignorelockingfailure ]
 .RB [ \-P | \-\-partial ]
 .RB [ \-v | \-\-verbose ]
 .RI [ VolumeGroupName ...]
 .SH DESCRIPTION
-.B vgcfgbackup
-allows you to backup the metadata 
-of your volume groups.
-If you don't name any volume groups on the command line, all of them 
+vgcfgbackup allows you to backup the metadata of your volume groups.
+If you don't name any volume groups on the command line, all of them
 will be backed up.
 .sp
 In a default installation, each volume group gets backed up into a separate
 file bearing the name of the volume group in the directory #DEFAULT_BACKUP_DIR#.
-You can write the backup to an alternative file using -f.  In this case
+You can write the backup to an alternative file using \fB-f\fP.  In this case
 if you are backing up more than one volume group the filename is
 treated as a template, and %s gets replaced by the volume group name.
 .sp
 NB. This DOESN'T backup user/system data in logical
 volume(s)!  Backup #DEFAULT_SYS_DIR# regularly too.
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .SH SEE ALSO
 .BR lvm (8),
 .BR vgcfgrestore (8)
index c62c81334fdf58869c0ef0381de7990eb33f552d..3b7b038b2356a1328ddb3ccf765e22b4fa28fbf4 100644 (file)
@@ -4,40 +4,43 @@ vgcfgrestore \- restore volume group descriptor area
 .SH SYNOPSIS
 .B vgcfgrestore
 .RB [ \-d | \-\-debug ]
-.RB [ \-f | \-\-file " filename" ]
-.RB [ \-l[l] | \-\-list ]
+.RB [ \-f | \-\-file
+.RI < filename >]
+.RB [ \-l [ l ]| \-\-list ]
 .RB [ \-h | \-\-help ]
-.RB [ \-M | \-\-Metadatatype 1|2]
+.RB [ \-M | \-\-metadatatype
+.IR 1 | 2 ]
 .RB [ \-t | \-\-test ]
 .RB [ \-v | \-\-verbose ]
 .RI \fIVolumeGroupName\fP
 .SH DESCRIPTION
-.B vgcfgrestore
-allows you to restore the metadata of \fIVolumeGroupName\fP from a text 
-backup file produced by \fBvgcfgbackup\fP.  You can specify a backup file 
-with \fP--file\fP.  If no backup file is specified, the most recent
-one is used.  Use \fB--list\fP for a list of the available
+vgcfgrestore allows you to restore the metadata of \fIVolumeGroupName\fP
+from a text backup file produced by \fBvgcfgbackup\fP.
+You can specify a backup file with \fB\-\-file\fP.
+If no backup file is specified, the most recent
+one is used.  Use \fB\-\-list\fP for a list of the available
 backup and archive files of \fIVolumeGroupName\fP.
 .SH OPTIONS
+See \fBlvm\fP(8) for common options.
 .TP
-\fB-l | --list\fP \(em List files pertaining to \fIVolumeGroupName\fP
+.BR \-l ", " \-\-list\fP
+List files pertaining to \fIVolumeGroupName\fP
 List metadata backup and archive files pertaining to \fIVolumeGroupName\fP.
-May be used with the \fB-f\fP option.  Does not restore \fIVolumeGroupName\fP.
+May be used with the \fB\-f\fP option.  Does not restore \fIVolumeGroupName\fP.
 .TP
-\fB-f | --file\fP filename \(em Name of LVM metadata backup file
+.BR \-f ", " \-\-file " " \fIfilename
+Name of LVM metadata backup file
 Specifies a metadata backup or archive file to be used for restoring 
 VolumeGroupName.  Often this file has been created with \fBvgcfgbackup\fP.
-.TP
-See \fBlvm\fP for common options.
 .SH REPLACING PHYSICAL VOLUMES
-\fBvgdisplay --partial --verbose\fP will show you the UUIDs and sizes of
+\fBvgdisplay \-\-partial \-\-verbose\fP will show you the UUIDs and sizes of
 any PVs that are no longer present.
 If a PV in the VG is lost and you wish to substitute 
 another of the same size, use 
-\fBpvcreate --restorefile filename --uuid uuid\fP (plus additional 
+\fBpvcreate \-\-restorefile filename \-\-uuid uuid\fP (plus additional 
 arguments as appropriate) to initialise it with the same UUID as 
 the missing PV.  Repeat for all other missing PVs in the VG. 
-Then use \fBvgcfgrestore --file filename\fP to restore the volume
+Then use \fBvgcfgrestore \-\-file filename\fP to restore the volume
 group's metadata.
 .SH SEE ALSO
 .BR lvm (8),
index b4313d484556583d186935ff1470bdb78fe38bda..0f5fc588c37f4d9911c6114b2f4011e1805b6f4d 100644 (file)
@@ -7,39 +7,45 @@ vgchange \- change attributes of a volume group
 .IR Tag ]
 .RB [ \-\-alloc
 .IR AllocationPolicy ]
-.RB [ \-A | \-\-autobackup " {" y | n }]
-.RB [ \-a | \-\-available " [e|l] {" y | n }]
-.RB [ \-\-monitor " {" y | n }]
-.RB [ \-\-poll " {" y | n }]
-.RB [ \-c | \-\-clustered " {" y | n }]
+.RB [ \-A | \-\-autobackup
+.RI { y | n }]
+.RB [ \-a | \-\-activate
+.RI [ a | e | l ]
+.RI { y | n }]
+.RB [ \-\-monitor
+.RI { y | n }]
+.RB [ \-\-poll
+.RI { y | n }]
+.RB [ \-c | \-\-clustered
+.RI { y | n }]
 .RB [ \-u | \-\-uuid ]
-.RB [ \-d | \-\-debug]
+.RB [ \-d | \-\-debug ]
 .RB [ \-\-deltag
 .IR Tag ]
-.RB [ \-h | \-\-help]
-.RB [ \-\-ignorelockingfailure]
-.RB [ \-\-ignoremonitoring]
-.RB [ \-\-sysinit]
+.RB [ \-h | \-\-help ]
+.RB [ \-\-ignorelockingfailure ]
+.RB [ \-\-ignoremonitoring ]
+.RB [ \-\-sysinit ]
 .RB [ \-\-noudevsync ]
 .RB [ \-l | \-\-logicalvolume
 .IR MaxLogicalVolumes ]
 .RB [ -p | \-\-maxphysicalvolumes
 .IR MaxPhysicalVolumes ]
-.RB [ \-\-[vg]metadatacopies ]
-.IR NumberOfCopies|unmanaged|all ]
-.RB [ \-P | \-\-partial]
+.RB [ \-\- [ vg ] metadatacopies ]
+.IR NumberOfCopies | unmanaged | all ]
+.RB [ \-P | \-\-partial ]
 .RB [ \-s | \-\-physicalextentsize
-.IR PhysicalExtentSize [ \fBbBsSkKmMgGtTpPeE\fR ]]
-.RB [ \-\-refresh]
-.RB [ -t | \-\-test]
-.RB [ \-v | \-\-verbose]
+.IR PhysicalExtentSize [ bBsSkKmMgGtTpPeE ]]
+.RB [ \-\-refresh ]
+.RB [ -t | \-\-test ]
+.RB [ \-v | \-\-verbose ]
 .RB [ \-\-version ]
-.RB [ \-x | \-\-resizeable " {" y | n }]
+.RB [ \-x | \-\-resizeable
+.RI { y | n }]
 .RI [ VolumeGroupName ...]
 .SH DESCRIPTION
-.B vgchange
-allows you to change the attributes of one or more volume groups.
-Its main purpose is to activate and deactivate
+vgchange allows you to change the attributes of one or more
+volume groups. Its main purpose is to activate and deactivate
 .IR VolumeGroupName ,
 or all volume groups if none is specified.  Only active volume groups
 are subject to changes and allow access to their logical volumes.
@@ -51,25 +57,30 @@ snapshots should be removed (see
 .BR lvremove (8)).
 ]
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .TP
-.BR \-A ", " \-\-autobackup " " { y | n }
+.BR \-A ", " \-\-autobackup " {" \fIy | \fIn }
 Controls automatic backup of metadata after the change.  See
-.B vgcfgbackup (8).
+.BR vgcfgbackup (8).
 Default is yes.
 .TP
-.BR \-a ", " \-\-available " " [e|l] { y | n }
-Controls the availability of the logical volumes in the volume 
+.BR \-a ", " \-\-activate " [" \fIa | \fIe | \fIl ]{ \fIy | \fIn }
+Controls the availability of the logical volumes in the volume
 group for input/output.
 In other words, makes the logical volumes known/unknown to the kernel.
+If autoactivation option is used (\-aay), each logical volume in
+the volume group is activated only if it matches an item in the
+activation/auto_activation_volume_list set in lvm.conf.
+Autoactivation is not yet supported for partial or clustered
+volume groups.
 .IP
 If clustered locking is enabled, add 'e' to activate/deactivate
 exclusively on one node or 'l' to activate/deactivate only
-on the local node.  
+on the local node.
 Logical volumes with single-host snapshots are always activated
 exclusively because they can only be used on one node at once.
 .TP
-.BR \-c ", " \-\-clustered " " { y | n }
+.BR \-c ", " \-\-clustered " {" \fIy | \fIn }
 If clustered locking is enabled, this indicates whether this
 Volume Group is shared with other nodes in the cluster or whether
 it contains only local disks that are not visible on the other nodes.
@@ -80,33 +91,41 @@ are not marked as clustered.
 .BR \-u ", " \-\-uuid
 Generate new random UUID for specified Volume Groups.
 .TP
-.BR \-\-monitor " " { y | n }
+.BR \-\-monitor " {" \fIy | \fIn }
 Start or stop monitoring a mirrored or snapshot logical volume with
 dmeventd, if it is installed.
 If a device used by a monitored mirror reports an I/O error,
-the failure is handled according to 
-.BR mirror_image_fault_policy
-and 
-.BR mirror_log_fault_policy
-set in 
+the failure is handled according to
+.B mirror_image_fault_policy
+and
+.B mirror_log_fault_policy
+set in
 .BR lvm.conf (5).
 .TP
-.BR \-\-poll " " { y | n }
+.BR \-\-poll " {" \fIy | \fIn }
 Without polling a logical volume's backgrounded transformation process
 will never complete.  If there is an incomplete pvmove or lvconvert (for
-example, on rebooting after a crash), use \fB--poll y\fP to restart the
+example, on rebooting after a crash), use \fB\-\-poll y\fP to restart the
 process from its last checkpoint.  However, it may not be appropriate to
-immediately poll a logical volume when it is activated, use \fB--poll
-n\fP to defer and then \fB--poll y\fP to restart the process.
+immediately poll a logical volume when it is activated, use 
+\fB\-\-poll n\fP to defer and then \fB\-\-poll y\fP to restart the process.
 .TP
 .BR \-\-sysinit
 Indicates that vgchange(8) is being invoked from early system initialisation
 scripts (e.g. rc.sysinit or an initrd), before writeable filesystems are
 available. As such, some functionality needs to be disabled and this option
 acts as a shortcut which selects an appropriate set of options. Currently
-this is equivalent to using  \fB--ignorelockingfailure\fP, \fB--ignoremonitoring\fP,
-\fB--poll n\fP and setting \fBLVM_SUPPRESS_LOCKING_FAILURE_MESSAGES\fP
+this is equivalent to using
+.BR \-\-ignorelockingfailure ,
+.BR \-\-ignoremonitoring ,
+.B \-\-poll n
+and setting \fBLVM_SUPPRESS_LOCKING_FAILURE_MESSAGES\fP
 environment variable.
+
+If \fB\-\-sysinit\fP is used in conjunction with lvmetad(8) enabled and running,
+autoactivation is preferred over manual activation via direct vgchange call.
+Logical volumes are autoactivated according to auto_activation_volume_list
+set in lvm.conf(5).
 .TP
 .BR \-\-noudevsync
 Disable udev synchronisation. The
@@ -116,16 +135,16 @@ in the background.  You should only use this if udev is not running
 or has rules that ignore the devices LVM2 creates.
 .TP
 .BR \-\-ignoremonitoring
-Make no attempt to interact with dmeventd unless 
+Make no attempt to interact with dmeventd unless
 .BR \-\-monitor
 is specified.
 Do not use this if dmeventd is already monitoring a device.
 .TP
-.BR \-l ", " \-\-logicalvolume " " \fIMaxLogicalVolumes\fR
+.BR \-l ", " \-\-logicalvolume " " \fIMaxLogicalVolumes
 Changes the maximum logical volume number of an existing inactive
 volume group.
 .TP
-.BR \-p ", " \-\-maxphysicalvolumes " " \fIMaxPhysicalVolumes\fR
+.BR \-p ", " \-\-maxphysicalvolumes " " \fIMaxPhysicalVolumes
 Changes the maximum number of physical volumes that can belong
 to this volume group.
 For volume groups with metadata in lvm1 format, the limit is 255.
@@ -135,7 +154,7 @@ a volume group with metadata in lvm2 format, for tool performance reasons,
 you should consider some use of \fB--pvmetadatacopies 0\fP as described in
 \fBpvcreate(8)\fP, and/or use \fB--vgmetadatacopies\fP.
 .TP
-.BR \-\-[vg]metadatacopies " " \fINumberOfCopies|unmanaged|all\fP
+.BR \-\- [ vg ] metadatacopies " " \fINumberOfCopies | \fIunmanaged | \fIall
 Sets the desired number of metadata copies in the volume group.  If set to
 a non-zero value, LVM will automatically manage the 'metadataignore'
 flags on the physical volumes (see \fBpvchange\fP or \fBpvcreate --metadataignore\fP) in order
@@ -147,26 +166,26 @@ The \fBvgmetadatacopies\fP option is useful for volume groups containing
 large numbers of physical volumes with metadata as it may be used to
 minimize metadata read and write overhead.
 .TP
-.BR \-s ", " \-\-physicalextentsize " " \fIPhysicalExtentSize\fR[\fBbBsSkKmMgGtTpPeE\fR]
+.BR \-s ", " \-\-physicalextentsize " " \fIPhysicalExtentSize [ \fIBbBsSkKmMgGtTpPeE ]
 Changes the physical extent size on physical volumes of this volume group.
 A size suffix (k for kilobytes up to t for terabytes) is optional, megabytes
 is the default if no suffix is present.
-The default is 4 MB and it must be at least 1 KB and a power of 2.
+The default is 4 MiB and it must be at least 1 KiB and a power of 2.
+
 Before increasing the physical extent size, you might need to use lvresize,
 pvresize and/or pvmove so that everything fits.  For example, every
-contiguous range of extents used in a logical volume must start and 
+contiguous range of extents used in a logical volume must start and
 end on an extent boundary.
+
 If the volume group metadata uses lvm1 format, extents can vary in size from
-8KB to 16GB and there is a limit of 65534 extents in each logical volume.  The
-default of 4 MB leads to a maximum logical volume size of around 256GB.
+8KiB to 16GiB and there is a limit of 65534 extents in each logical volume.
+The default of 4 MiB leads to a maximum logical volume size of around 256GiB.
+
 If the volume group metadata uses lvm2 format those restrictions do not apply,
 but having a large number of extents will slow down the tools but have no
-impact on I/O performance to the logical volume.  The smallest PE is 1KB.
-The 2.4 kernel has a limitation of 2TB per block device.
+impact on I/O performance to the logical volume.  The smallest PE is 1KiB.
+
+The 2.4 kernel has a limitation of 2TiB per block device.
 .TP
 .BR \-\-refresh
 If any logical volume in the volume group is active, reload its metadata.
@@ -174,24 +193,20 @@ This is not necessary in normal operation, but may be useful
 if something has gone wrong or if you're doing clustering
 manually without a clustered lock manager.
 .TP
-.BR \-x ", " \-\-resizeable " " { y | n }
+.BR \-x ", " \-\-resizeable " {" \fIy | \fIn }
 Enables or disables the extension/reduction of this volume group
 with/by physical volumes.
-.SH EXAMPLES
+.SH Examples
 To activate all known volume groups in the system:
-.nf
-
-\      vgchange -a y
+.sp
+.B vgchange -a y
 
-.fi
 To change the maximum number of logical volumes of inactive volume group
-.B vg00
-to 128.
-.nf
+vg00 to 128.
+.sp
+.B vgchange -l 128 /dev/vg00
 
-\      vgchange -l 128 /dev/vg00
 
-.fi
 .SH SEE ALSO
 .BR lvchange (8),
 .BR lvm (8),
index 2e5d92620eda4b638c2f62b79027df7013abe185..cc6cd578dd5234a0578b800d6356414bb8e0df9f 100644 (file)
@@ -3,11 +3,14 @@
 vgck \- check volume group metadata
 .SH SYNOPSIS
 .B vgck
-[\-d|\-\-debug] [\-h|\-?|\-\-help] [\-v|\-\-verbose] [VolumeGroupName...]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-v | \-\-verbose ]
+.RI [ VolumeGroupName ...]
 .SH DESCRIPTION
 vgck checks LVM metadata for each named volume group for consistency.
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .SH SEE ALSO
 .BR lvm (8),
 .BR vgcreate (8),
index 14e95f409b766c41b68b48ada9141226cefa2640..95ea41c426e6507dbfd55c535c1c4f3ede8c1828 100644 (file)
@@ -8,29 +8,32 @@ vgconvert \- convert volume group metadata format
 .RB [ \-t | \-\-test ]
 .RB [ \-v | \-\-verbose ]
 .RB [ \-\-labelsector ]
-.RB [ \-M | \-\-metadatatype type ]
-.RB [ \-\-pvmetadatacopies #copies ]
-.RB [ \-\-metadatasize size ]
+.RB [ \-M | \-\-metadatatype
+.IR type ]
+.RB [ \-\-pvmetadatacopies
+.IR NumberOfCopies ]
+.RB [ \-\-metadatasize
+.IR size ]
 .RB [ \-\-version ]
-.IR VolumeGroupName " [" VolumeGroupName ...]
+.I VolumeGroupName
+.RI [ VolumeGroupName ...]
 .SH DESCRIPTION
-.B vgconvert
-converts 
+vgconvert converts
 .I VolumeGroupName
 metadata from one format to another provided that the metadata
 fits into the same space.
 .SH OPTIONS
 See \fBlvm\fP(8) and \fBpvcreate\fP(8) for options.
-.SH EXAMPLE
-Convert volume group vg1 from LVM1 metadata format to the new LVM2 
+.SH Examples
+Convert volume group vg1 from LVM1 metadata format to the new LVM2
 metadata format.
 .sp
-.B vgconvert -M2 vg1
+.B vgconvert \-M2 vg1
 .SH RECOVERY
 Use \fBpvscan\fP(8) to see which PVs lost their metadata.
-Run \fBpvcreate\fP(8) with the --uuid and --restorefile options on each
-such PV to reformat it as it was, using the archive file that
-\fBvgconvert\fP(8) created at the start of the procedure.
+Run \fBpvcreate\fP(8) with the \fB\-\-uuid\fP and \fB\-\-restorefile\fP
+options on each such PV to reformat it as it was, using the archive
+file that \fBvgconvert\fP(8) created at the start of the procedure.
 Finally run \fBvgcfgrestore\fP(8) with that archive file to restore
 the original metadata.
 .SH SEE ALSO
index 5ac5e2a55f486ff3d9433760ace8e5b4eeeb545a..577fee22d5e7b17fd47562cc836597a8fda88a4c 100644 (file)
@@ -5,79 +5,83 @@ vgcreate \- create a volume group
 .B vgcreate
 .RB [ \-\-addtag
 .IR Tag ]
-.RB [ \-\-alloc 
+.RB [ \-\-alloc
 .IR AllocationPolicy ]
-.RB [ \-A | \-\-autobackup " {" y | n }]
-.RB [ \-c | \-\-clustered " {" y | n }]
+.RB [ \-A | \-\-autobackup
+.RI { y | n }]
+.RB [ \-c | \-\-clustered
+.RI { y | n }]
 .RB [ \-d | \-\-debug ]
 .RB [ \-h | \-\-help ]
 .RB [ \-l | \-\-maxlogicalvolumes
 .IR MaxLogicalVolumes ]
-.RB [ -M | \-\-metadatatype type]
+.RB [ -M | \-\-metadatatype
+.IR type ]
 .RB [ -p | \-\-maxphysicalvolumes
 .IR MaxPhysicalVolumes ]
-.RB [ \-\-[vg]metadatacopies ]
-.IR NumberOfCopies|unmanaged|all ]
+.RB [ \-\- [ vg ] metadatacopies
+.IR NumberOfCopies | unmanaged | all ]
 .RB [ \-s | \-\-physicalextentsize
-.IR PhysicalExtentSize [ \fBbBsSkKmMgGtTpPeE\fR ]]
+.IR PhysicalExtentSize [ bBsSkKmMgGtTpPeE ]]
 .RB [ \-t | \-\-test ]
 .RB [ \-v | \-\-verbose ]
 .RB [ \-\-version ]
-[ \fIPHYSICAL DEVICE OPTIONS\fP ]
+.RB [ "PHYSICAL DEVICE OPTIONS" ]
 .I VolumeGroupName PhysicalDevicePath
 .RI [ PhysicalDevicePath ...]
 .SH DESCRIPTION
-.B vgcreate
-creates a new volume group called
+vgcreate creates a new volume group called
 .I VolumeGroupName
 using the block special device \fIPhysicalDevicePath\fP.
 .sp
 If \fIPhysicalDevicePath\fP was not previously configured for LVM with
-\fBpvcreate (8)\fP, the device will be initialized with the same
-default values used with \fBpvcreate\fP.  If non-default
+\fBpvcreate\fP(8), the device will be initialized with the same
+default values used with \fBpvcreate\fP(8).  If non-default
 \fPpvcreate\fP values are desired, they may be given on the
-commandline with the same options as \fPpvcreate\fP.  See
-\fBPHYSICAL DEVICE OPTIONS\fP for available options.  Note
-that the restore-related options such as --restorefile, --uuid,
-and --physicalvolumesize are not available.  If a restore operation
-is needed, use \fBpvcreate (8)\fP and \fBvgcfgrestore (8)\fP.
+commandline with the same options as \fBpvcreate\fP(8).  See
+.B PHYSICAL DEVICE OPTIONS
+for available options.  Note that the restore-related options such as
+.BR \-\-restorefile ", " \-\-uuid " and " \-\-physicalvolumesize
+are not available.  If a restore operation is needed, use 
+\fBpvcreate\fP(8) and \fBvgcfgrestore\fP(8).
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .TP
-.BR \-c ", " \-\-clustered " " { y | n }
-If clustered locking is enabled, this defaults to \fBy\fP indicating that 
+.BR \-c ", " \-\-clustered " {" \fIy | \fIn }
+If clustered locking is enabled, this defaults to \fBy\fP indicating that
 this Volume Group is shared with other nodes in the cluster.
 
-If the new Volume Group contains only local disks that are not visible 
+If the new Volume Group contains only local disks that are not visible
 on the other nodes, you must specify \fB\-\-clustered\ n\fP.
 If the cluster infrastructure is unavailable on a particular node at a
 particular time, you may still be able to use such Volume Groups.
 .TP
-.BR \-l ", " \-\-maxlogicalvolumes " " \fIMaxLogicalVolumes\fR
+.BR \-l ", " \-\-maxlogicalvolumes " " \fIMaxLogicalVolumes
 Sets the maximum number of logical volumes allowed in this
-volume group. 
-The setting can be changed with \fBvgchange\fP.
+volume group.
+The setting can be changed with \fBvgchange\fP(8).
 For volume groups with metadata in lvm1 format, the limit
-and default value is 255.  
+and default value is 255.
 If the metadata uses lvm2 format, the default value is 0
 which removes this restriction: there is then no limit.
 .TP
-.BR \-p ", " \-\-maxphysicalvolumes " " \fIMaxPhysicalVolumes\fR
+.BR \-p ", " \-\-maxphysicalvolumes " " \fIMaxPhysicalVolumes
 Sets the maximum number of physical volumes that can belong
 to this volume group.
 The setting can be changed with \fBvgchange\fP.
 For volume groups with metadata in lvm1 format, the limit
-and default value is 255.  
+and default value is 255.
 If the metadata uses lvm2 format, the value 0 removes this restriction:
 there is then no limit.  If you have a large number of physical volumes in
 a volume group with metadata in lvm2 format, for tool performance reasons,
-you should consider some use of \fB--pvmetadatacopies 0\fP as described in
-\fBpvcreate(8)\fP, and/or use \fB--vgmetadatacopies\fP.
+you should consider some use of \fB\-\-pvmetadatacopies 0\fP as described in
+\fBpvcreate\fP(8), and/or use \fB\-\-vgmetadatacopies\fP.
 .TP
-.BR \-\-vgmetadatacopies " " \fINumberOfCopies|unmanaged|all\fP
+.BR \-\- [ vg ] metadatacopies " " \fINumberOfCopies | \fIunmanaged | \fIall
 Sets the desired number of metadata copies in the volume group.  If set to
 a non-zero value, LVM will automatically manage the 'metadataignore'
-flags on the physical volumes (see \fBpvcreate\fP or \fBpvchange\fP --metadataignore\fP) in order
+flags on the physical volumes (see \fBpvcreate\fP(8) or
+\fBpvchange \-\-metadataignore\fP) in order
 to achieve \fINumberOfCopies\fP copies of metadata.  If set to \fIunmanaged\fP,
 LVM will not automatically manage the 'metadataignore' flags.  If set to
 \fIall\fP, LVM will first clear all of the 'metadataignore' flags on all
@@ -87,56 +91,53 @@ large numbers of physical volumes with metadata as it may be used to
 minimize metadata read and write overhead.
 The default value is \fIunmanaged\fP.
 .TP
-.BR \-s ", " \-\-physicalextentsize " " \fIPhysicalExtentSize\fR[\fBbBsSkKmMgGtTpPeE\fR]
+.BR \-s ", " \-\-physicalextentsize " " \fIPhysicalExtentSize [ \fIbBsSkKmMgGtTpPeE ]
 Sets the physical extent size on physical volumes of this volume group.
 A size suffix (k for kilobytes up to t for terabytes) is optional, megabytes
-is the default if no suffix is present.  
-The default is 4 MB and it must be at least 1 KB and a power of 2.
+is the default if no suffix is present.
+The default is 4 MiB and it must be at least 1 KiB and a power of 2.
 
 Once this value has been set, it is difficult to change it without recreating
-the volume group which would involve backing up and restoring data on any 
+the volume group which would involve backing up and restoring data on any
 logical volumes.  However, if no extents need moving for the new
-value to apply, it can be altered using vgchange \-s.
+value to apply, it can be altered using \fBvgchange \-s\fP.
 
 If the volume group metadata uses lvm1 format, extents can vary in size from
-8KB to 16GB and there is a limit of 65534 extents in each logical volume.  The
-default of 4 MB leads to a maximum logical volume size of around 256GB.  
+8KiB to 16GiB and there is a limit of 65534 extents in each logical volume.  The
+default of 4 MiB leads to a maximum logical volume size of around 256GiB.
 
 If the volume group metadata uses lvm2 format those restrictions do not apply,
 but having a large number of extents will slow down the tools but have no
-impact on I/O performance to the logical volume.  The smallest PE is 1KB.
+impact on I/O performance to the logical volume.  The smallest PE is 1KiB
+
+The 2.4 kernel has a limitation of 2TiB per block device.
 
-The 2.4 kernel has a limitation of 2TB per block device.
 .SH PHYSICAL DEVICE OPTIONS
 The following options are available for initializing physical devices in the
-volume group.  These options are further described in the pvcreate man page.
+volume group.  These options are further described in the \fBpvcreate\fP(8)
+man page.
 .TP
 .BR \-f ", " \-\-force
 .TP
 .BR \-y ", " \-\-yes
 .TP
-.BR \-Z ", " \-\-zero " y|n"
+.BR \-Z ", " \-\-zero " {" \fIy | \fIn }
 .TP
-.BR \-\-labelsector " sector"
+.B \-\-labelsector \fIsector
 .TP
-.BR \-\-metadatasize " size"
+.B \-\-metadatasize \fIsize
 .TP
-.BR \-\-pvmetadatacopies " copies"
+.B \-\-pvmetadatacopies \fIcopies
 .TP
-.BR \-\-dataalignment " alignment"
+.B \-\-dataalignment \fIalignment
 .TP
-.BR \-\-dataalignmentoffset " alignment_offset"
-.SH EXAMPLES
-To create a volume group named
-.B test_vg 
-using physical volumes
-.BR /dev/sdk1 ", and " /dev/sdl1
-with default physical extent size of 4MB:
-.nf
-
-\      vgcreate test_vg /dev/sdk1 /dev/sdl1
+.B \-\-dataalignmentoffset \fIalignment_offset
+.SH Examples
+Creates a volume group named "test_vg" using physical volumes "/dev/sdk1"
+and "/dev/sdl1" with default physical extent size of 4MiB:
+.sp
+.B vgcreate test_vg /dev/sdk1 /dev/sdl1
 
-.fi
 .SH SEE ALSO
 .BR lvm (8),
 .BR pvdisplay (8),
index 96dfe8c8fa15a6ca2a4e057dc7bd60f5f10791eb..70c1fa71f170eeeb00e88c9e066fec84d270793b 100644 (file)
@@ -4,41 +4,54 @@ vgdisplay \- display attributes of volume groups
 .SH SYNOPSIS
 .B vgdisplay
 .RB [ \-A | \-\-activevolumegroups ]
-.RB [ \-c | \-\-colon | \-s | \-\-short | \-v|\-\-verbose ]
+.RB [ \-c | \-\-colon ]
+.RB [ \-s | \-\-short ]
+.RB [ \-v | \-\-verbose ]
 .RB [ \-d | \-\-debug ]
 .RB [ \-h | \-\-help ]
 .RB [ \-\-ignorelockingfailure ]
 .RB [ \-\-nosuffix ]
 .RB [ \-P | \-\-partial ]
-.RB [\-\-units hHbBsSkKmMgGtTpPeE]
+.RB [ \-\-units
+.IR hHbBsSkKmMgGtTpPeE ]
 .RB [ \-\-version ]
-.RI [VolumeGroupName [VolumeGroupName...]]
+.RI [ VolumeGroupName
+.RI [ VolumeGroupName ...]]
 .br
 
 .br
-.B vgdisplay \-\-columns | \-C
-.RB [ \-\-aligned ] [ \-d|\-\-debug ] [ \-h|\-?|\-\-help ]
-.RB [ \-\-ignorelockingfailure ] [ \-\-noheadings ] [ \-\-nosuffix ]
-.RB [ \-o|\-\-options [+]Field[,Field] ]
-.RB [ \-O|\-\-sort [+|-]Key1[,[+|-]Key2[,...]] ]
-.RB [ \-P|\-\-partial ]
-.RB [ \-\-separator Separator ]
+.B vgdisplay
+.BR \-\-columns | \-C
+.RB [ \-\-aligned ]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-\-ignorelockingfailure ]
+.RB [ \-\-noheadings ]
+.RB [ \-\-nosuffix ]
+.RB [ \-o|\-\-options
+.RI [ + ] Field1 [ ,Field2 ...]]
+.RB [ \-O | \-\-sort
+.RI [ + | - ] Key1 [ , [ + | - ] Key2 ...]]
+.RB [ \-P | \-\-partial ]
+.RB [ \-\-separator
+.IR Separator ]
 .RB [ \-\-unbuffered ]
-.RB [ \-\-units hHbBsSkKmMgGtTpPeE ]
-.RB [ \-v|\-\-verbose ]
+.RB [ \-\-units
+.IR hHbBsSkKmMgGtTpPeE ]
+.RB [ \-v | \-\-verbose ]
 .RB [ \-\-version ]
-.RI [VolumeGroupName [VolumeGroupName...]]
+.RI [ VolumeGroupName
+.RI [ VolumeGroupName ...]]
 .SH DESCRIPTION
-.B vgdisplay
-allows you to see the attributes of
+vgdisplay allows you to see the attributes of
 .I VolumeGroupName
 (or all volume groups if none is given) with it's physical and logical
 volumes and their sizes etc.
 .P
-\fBvgs\fP (8) is an alternative that provides the same information 
-in the style of \fBps\fP (1).
+\fBvgs\fP(8) is an alternative that provides the same information
+in the style of \fBps\fP(1).
 .SH OPTIONS
-See \fBlvm\fP for common options and \fBvgs\fP for options given with
+See \fBlvm\fP(8) for common options and \fBvgs\fP(8) for options given with
 \fB\-\-columns\fP.
 .TP
 .BR \-A ", " \-\-activevolumegroups
@@ -46,7 +59,7 @@ Only select the active volume groups.
 .TP
 .BR \-c ", " \-\-colon
 Generate colon separated output for easier parsing in scripts or programs.
-N.B. \fBvgs\fP (8) provides considerably more control over the output.
+N.B. \fBvgs\fP(8) provides considerably more control over the output.
 .nf
 
 The values are:
@@ -79,12 +92,12 @@ Display verbose information containing long listings of physical
 and logical volumes.  If given twice, also display verbose runtime
 information of vgdisplay's activities.
 .TP
-.BR \-\-version
+.B \-\-version
 Display version and exit successfully.
 .TP
 .BR \-\-columns | \-C
-Display output in columns, the equivalent of \fBvgs\fP.  Options listed
-are the same as options given in \fPvgs (8)\fP.
+Display output in columns, the equivalent of \fBvgs\fP(8). 
+Options listed are the same as options given in \fPvgs\fP(8).
 .SH SEE ALSO
 .BR lvm (8),
 .BR vgs (8),
index 27ce57728a7c86012b407dbde50f7c3b645888bd..75091706a3a558b17427c53e59553bf64575fc4c 100644 (file)
@@ -3,12 +3,14 @@
 vgexport \- make volume groups unknown to the system
 .SH SYNOPSIS
 .B vgexport
-[\-a|\-\-all]
-[\-d|\-\-debug] [\-h|\-?|\-\-help] 
-[\-v|\-\-verbose]
-VolumeGroupName [VolumeGroupName...]
+.RB [ \-a | \-\-all ]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-v | \-\-verbose ]
+.I VolumeGroupName
+.RI [ VolumeGroupName ...]
 .SH DESCRIPTION
-vgexport allows you to make the inactive 
+vgexport allows you to make the inactive
 .IR VolumeGroupName (s)
 unknown to the system.
 You can then move all the Physical Volumes in that Volume Group to
@@ -16,9 +18,9 @@ a different system for later
 .BR vgimport (8).
 Most LVM2 tools ignore exported Volume Groups.
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .TP
-.I \-a, \-\-all
+.BR \-a ", " \-\-all
 Export all inactive Volume Groups.
 .SH SEE ALSO
 .BR lvm (8),
index 4ae2f089a5b20eeaa90dd5ab88116f30c8a75755..ebb642f4249b189fa1784af6ae8f43fcac24950c 100644 (file)
@@ -3,58 +3,63 @@
 vgextend \- add physical volumes to a volume group
 .SH SYNOPSIS
 .B vgextend
-[\-A|\-\-autobackup y|n] [\-d|\-\-debug] [\-h|\-?|\-\-help] 
-[\-\-restoremissing]
-[\-f|\-\-force]
-[\-t|\-\-test]
-[\-v|\-\-verbose]
-[ \fIPHYSICAL DEVICE OPTIONS\fP ]
-VolumeGroupName PhysicalDevicePath [PhysicalDevicePath...]
+.RB [ \-A | \-\-autobackup
+.RI { y | n }]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-\-restoremissing ]
+.RB [ \-f | \-\-force ]
+.RB [ \-t | \-\-test ]
+.RB [ \-v | \-\-verbose ]
+.RB [ "PHYSICAL DEVICE OPTIONS" ]
+.I VolumeGroupName PhysicalDevicePath
+.RI [ PhysicalDevicePath ...]
 .SH DESCRIPTION
-vgextend allows you to add one or more initialized physical volumes ( see
-.B pvcreate(8)
-) to an existing volume group to extend it in size. Moreover, it allows you to
+vgextend allows you to add one or more initialized physical volumes
+(see \fBpvcreate\fP(8)) to an existing volume group to extend it in size. Moreover, it allows you to
 re-add a physical volume that has gone missing previously, due to a transient
-device failure, without re-initialising it. Use vgextend \-\-restoremissing to
-that effect.
+device failure, without re-initialising it. Use
+\fBvgextend \-\-restoremissing\fP to that effect.
 .sp
 If \fIPhysicalDevicePath\fP was not previously configured for LVM with
-\fBpvcreate (8)\fP, the device will be initialized with the same
-default values used with \fBpvcreate\fP.  If non-default
-\fPpvcreate\fP values are are desired, they may be given on the
-commandline with the same options as \fPpvcreate\fP.  See
-\fBPHYSICAL DEVICE OPTIONS\fP for available options.  Note
-that the restore-related options such as --restorefile, --uuid,
-and --physicalvolumesize are not available.  If a restore operation
-is needed, use \fBpvcreate (8)\fP and \fBvgcfgrestore (8)\fP.
+\fBpvcreate\fP(8), the device will be initialized with the same
+default values used with \fBpvcreate\fP(8).  If non-default
+\fPpvcreate\fP(8) values are desired, they may be given on the
+commandline with the same options as \fPpvcreate\fP(8).  See
+.B PHYSICAL DEVICE OPTIONS
+for available options.  Note that the restore-related options such as
+.BR \-\-restorefile ", " \-\-uuid " and " \-\-physicalvolumesize
+are not available.  If a restore operation
+is needed, use \fBpvcreate\fP(8) and \fBvgcfgrestore\fP(8).
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .SH PHYSICAL DEVICE OPTIONS
 The following options are available for initializing physical devices in the
-volume group.  These options are further described in the pvcreate man page.
+volume group.  These options are further described in the
+\fBpvcreate\fP(8) man page.
 .TP
 .BR \-f ", " \-\-force
 .TP
 .BR \-y ", " \-\-yes
 .TP
-.BR \-Z ", " \-\-zero " y|n"
+.BR \-Z ", " \-\-zero " {" \fIy | \fIn }
 .TP
-.BR \-\-labelsector " sector"
+.B \-\-labelsector \fIsector
 .TP
-.BR \-\-metadatasize " size"
+.B \-\-metadatasize \fIsize
 .TP
-.RB [ \-\-metadataignore y|n ]
+.BR \-\-metadataignore " {" \fIy | \fIn }
 .TP
-.BR \-\-pvmetadatacopies " copies"
+.B \-\-pvmetadatacopies \fIcopies
 .TP
-.BR \-\-dataalignment " alignment"
+.B \-\-dataalignment \fIalignment
 .TP
-.BR \-\-dataalignmentoffset " alignment_offset"
+.B \-\-dataalignmentoffset \fIalignment_offset
 .SH Examples
-"vgextend vg00 /dev/sda4 /dev/sdn1" tries to extend the existing volume
-group "vg00" by the new physical volumes (see
-.B pvcreate(8)
-) "/dev/sdn1" and /dev/sda4".
+Extends the existing volume group "vg00" by the new physical volumes
+(see \fBpvcreate\fP(8)) "/dev/sda4" and "/dev/sdn1".
+.sp
+.B vgextend vg00 /dev/sda4 /dev/sdn1
 .SH SEE ALSO
 .BR lvm (8),
 .BR vgcreate (8),
index ede639436d1a020584dc4161f52dab25dd001a50..dd781dea83974abd4b29f07e02320925c56710bf 100644 (file)
@@ -3,20 +3,22 @@
 vgimport \- make exported volume groups known to the system
 .SH SYNOPSIS
 .B vgimport
-[\-a|\-\-all]
-[\-d|\-\-debug] [\-h|\-?|\-\-help] 
-[\-v|\-\-verbose]
-VolumeGroupName [VolumeGroupName...]
+.RB [ \-a | \-\-all ]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-v | \-\-verbose ]
+.I VolumeGroupName
+.RI [ VolumeGroupName ...]
 .SH DESCRIPTION
-.B vgimport
-allows you to make a Volume Group that was previously exported using
+vgimport allows you to make a Volume Group that was previously
+exported using
 .BR vgexport (8)
 known to the system again, perhaps after moving its Physical Volumes
 from a different machine.
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .TP
-.I \-a, \-\-all
+.BR \-a ", " \-\-all
 Import all exported Volume Groups.
 .SH SEE ALSO
 .BR lvm (8),
index 7b84df4d08785da86d67628d936766db84852304..52ff079ad2f0777edb388f8d41246dcc0d2e2537 100644 (file)
@@ -3,55 +3,44 @@
 vgimportclone \- import and rename duplicated volume group (e.g. a hardware snapshot)
 .SH SYNOPSIS
 .B vgimportclone
-[\-n|\-\-basevgname VolumeGroupName]
-[\-i|\-\-import]
-PhysicalVolume [PhysicalVolume...]
+.RB [ \-n | \-\-basevgname
+.IR VolumeGroupName ]
+.RB [ \-i | \-\-import ]
+.I PhysicalVolume
+.RI [ PhysicalVolume ...]
 .SH DESCRIPTION
-.B vgimportclone
-is used to import a duplicated VG (e.g. hardware snapshot).  Duplicate VG(s)
-and PV(s) are not able to be used until they are made to coexist with
-the origin VG(s) and PV(s).   
-.B vgimportclone 
-renames the VG associated with the specified PV(s) and changes the
-associated VG and PV UUIDs.
+vgimportclone is used to import a duplicated VG (e.g. hardware snapshot).
+Duplicate VG(s) and PV(s) are not able to be used until they are made
+to coexist with the origin VG(s) and PV(s).
+vgimportclone renames the VG associated with the specified PV(s) and
+changes the associated VG and PV UUIDs.
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .TP
-.I \-n|\-\-basevgname VolumeGroupName
+.BR \-n ", " \-\-basevgname " " \fIVolumeGroupName
 By default the snapshot VG will be renamed to the original name plus a
 numeric suffix to avoid duplicate naming (e.g. 'test_vg' would be renamed
 to 'test_vg1').  This option will override the base VG name that is
 used for all VG renames.  If a VG already exists with the specified name
 a numeric suffix will be added (like the previous example) to make it unique.
 .TP
-.I \-i|\-\-import
+.BR \-i ", " \-\-import
 Import exported Volume Groups.  Otherwise VGs that have been exported
 will not be changed (nor will their associated PVs).
 .SH ENVIRONMENT VARIABLES
 .TP
-\fBLVM_BINARY\fP
-The LVM2 binary to use.
-Defaults to "lvm".
-.SH EXAMPLES
-The origin VG
-.B vg00
-has origin PVs
-.BR /dev/sda " and " /dev/sdb
-and the respective snapshot PVs are
-.BR /dev/sdc " and " /dev/sdd "."
-To rename the VG
-associated with
-.BR /dev/sdc " and " /dev/sdd
-from
-.B vg00
-to
-.B vg00_snap
+.B LVM_BINARY
+The LVM2 binary to use. Defaults to "lvm".
+.SH Examples
+The origin VG "vg00" has origin PVs "/dev/sda" and "/dev/sdb"
+and the respective snapshot PVs are "/dev/sdc" and "/dev/sdd".
+To rename the VG associated with "/dev/sdc" and "/dev/sdd"
+from "vg00" to "vg00_snap"
 (and to change associated VG and PV UUIDs) do:
-.nf
-
-\      vgimportclone --basevgname vg00_snap /dev/sdc /dev/sdd
+.sp
+.B vgimportclone --basevgname vg00_snap /dev/sdc /dev/sdd
 
-.fi
 .SH SEE ALSO
-.BR lvm (8)
+.BR lvm (8),
+.BR vgrename (8)
 
index bf1738b163047801c70f1c38361e9e4a890d8ce6..70db2954adbc676f2d2cf3376ae7e9aab7f3b3af 100644 (file)
@@ -3,25 +3,35 @@
 vgmerge \- merge two volume groups
 .SH SYNOPSIS
 .B vgmerge
-[\-A|\-\-autobackup y|n] [\-d|\-\-debug] [\-h|\-?|\-\-help] [\-l|\-\-list]
-[\-t|\-\-test] [\-v|\-\-verbose] DestinationVolumeGroupName
-SourceVolumeGroupName
+.RB [ \-A | \-\-autobackup
+.RI { y | n }]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-l | \-\-list ]
+.RB [ \-t | \-\-test ]
+.RB [ \-v | \-\-verbose ]
+.I DestinationVolumeGroupName
+.I SourceVolumeGroupName
 .SH DESCRIPTION
-vgmerge merges two existing volume groups. The inactive SourceVolumeGroupName
-will be merged into the DestinationVolumeGroupName if physical extent sizes
+vgmerge merges two existing volume groups. The inactive
+\fISourceVolumeGroupName\fP will be merged into 
+the \fIDestinationVolumeGroupName\fP if physical extent sizes
 are equal and physical and logical volume summaries of both volume groups
-fit into DestinationVolumeGroupName's limits.
+fit into \fIDestinationVolumeGroupName\fP's limits.
 .SH OPTIONS
-See \fBlvm\fP for common options.
-.I \-l, \-\-list
-Display merged DestinationVolumeGroupName like "vgdisplay -v".
+See \fBlvm\fP(8) for common options.
+.TP
+.BR \-l ", " \-\-list
+Display merged \fIDestinationVolumeGroupName\fP like \fBvgdisplay -v\fP.
 .TP 
-.I \-t, \-\-test
+.BR \-t ", " \-\-test
 Do a test run WITHOUT making any real changes.
 .SH Examples
-"vgmerge -v databases my_vg" merges the inactive volume group named "my_vg" 
+Merge the inactive volume group named "my_vg"
 into the active or inactive volume group named "databases" giving verbose
-runtime information.
+runtime information:
+.sp
+.B vgmerge -v databases my_vg
 .SH SEE ALSO
 .BR lvm (8),
 .BR vgcreate (8),
index 49f6a9dbc3c95e475da8369335c86b8d25144683..a0d9583f9479e577552376627383d00f08e7a217 100644 (file)
@@ -3,23 +3,23 @@
 vgmknodes \- recreate volume group directory and logical volume special files
 .SH SYNOPSIS
 .B vgmknodes
-.RB [ \-d | \-\-debug]
-.RB [ \-h | \-\-help]
-.RB [ \-\-refresh]
-.RB [ \-v | \-\-verbose]
-[[VolumeGroupName | LogicalVolumePath]...]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-\-help ]
+.RB [ \-\-refresh ]
+.RB [ \-v | \-\-verbose ]
+.RI [[ VolumeGroupName | LogicalVolumePath ]...]
 .SH DESCRIPTION
 Checks the LVM2 special files in /dev that are needed for active 
 logical volumes and creates any missing ones and removes unused ones.
 .SH OPTIONS
 .TP
+See \fBlvm\fP(8) for common options.
+.TP
 .BR \-\-refresh
 If any logical volume in the volume group is active, reload its metadata.
 This is not necessary in normal operation, but may be useful
 if something has gone wrong or if you're doing clustering
 manually without a clustered lock manager.
-.TP
-See \fBlvm\fP for common options.
 .SH SEE ALSO
 .BR lvm (8),
 .BR vgscan (8),
index f4f5d831f2bfb8714d80c2c85cc0d288e1ea300a..734f01eeb4b0aa45dc7b362e9cd2d063e9a6a44b 100644 (file)
@@ -3,28 +3,34 @@
 vgreduce \- reduce a volume group
 .SH SYNOPSIS
 .B vgreduce
-[\-a|\-\-all] [\-A|\-\-autobackup y|n] [\-d|\-\-debug] [\-h|\-?|\-\-help]
-[\-\-removemissing]
-[\-t|\-\-test]
-[\-v|\-\-verbose] VolumeGroupName
-[PhysicalVolumePath...]
+.RB [ \-a | \-\-all ]
+.RB [ \-A | \-\-autobackup
+.RI { y | n }]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-\-removemissing ]
+.RB [ \-t | \-\-test ]
+.RB [ \-v | \-\-verbose ]
+.I VolumeGroupName
+.RI [ PhysicalVolumePath ...]
 .SH DESCRIPTION
 vgreduce allows you to remove one or more unused physical volumes
 from a volume group.
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .TP
-.I \-a, \-\-all
+.BR \-a ", " \-\-all
 Removes all empty physical volumes if none are given on command line.
 .TP
-.I \-\-removemissing
+.B \-\-removemissing
 Removes all missing physical volumes from the volume group, if there are no
 logical volumes allocated on those. This resumes normal operation of the volume
 group (new logical volumes may again be created, changed and so on).
 
 If this is not possible (there are logical volumes referencing the missing
 physical volumes) and you cannot or do not want to remove them manually, you
-can run this option with --force to have vgreduce remove any partial LVs.
+can run this option with \fB--force\fP to have \fBvgreduce\fP
+remove any partial LVs.
 
 Any logical volumes and dependent snapshots that were partly on the 
 missing disks get removed completely. This includes those parts 
@@ -32,7 +38,7 @@ that lie on disks that are still present.
 
 If your logical volumes spanned several disks including the ones that are
 lost, you might want to try to salvage data first by activating your
-logical volumes with --partial as described in \fBlvm (8)\fP.
+logical volumes with \fB--partial\fP as described in \fBlvm\fP(8).
 
 .SH SEE ALSO
 .BR lvm (8),
index 0ec6510e9bb85c95b30b1b74e6c4b755544dda96..c205e8af2611f3a76d68660ffbd9b0d6635812ab 100644 (file)
@@ -3,9 +3,14 @@
 vgremove \- remove a volume group
 .SH SYNOPSIS
 .B vgremove
-[\-d|\-\-debug] [\-f|\-\-force] [\-h|\-?|\-\-help]
-[\-\-noudevsync] [\-t|\-\-test] [\-v|\-\-verbose]
-VolumeGroupName [VolumeGroupName...]
+.RB [ \-d | \-\-debug ]
+.RB [ \-f | \-\-force ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-\-noudevsync ]
+.RB [ \-t | \-\-test ]
+.RB [ \-v | \-\-verbose ]
+.I VolumeGroupName
+.RI [ VolumeGroupName ...]
 .SH DESCRIPTION
 vgremove allows you to remove one or more volume groups.
 If one or more physical volumes in the volume group are lost,
@@ -16,7 +21,7 @@ If there are logical volumes that exist in the volume group,
 a prompt will be given to confirm removal.  You can override
 the prompt with \fB-f\fP.
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .TP
 .BR \-f ", " \-\-force
 Force the removal of any logical volumes on the volume group
index 3fabbbb51a8f4b7413764d5a6b611634958009e7..379f697084840e73e641b15f688cfed506a10da3 100644 (file)
@@ -3,32 +3,21 @@
 vgrename \- rename a volume group
 .SH SYNOPSIS
 .B vgrename
-[\-A|\-\-autobackup y|n]
-[\-d|\-\-debug]
-[\-h|\-?|\-\-help]
-[\-t|\-\-test]
-[\-v|\-\-verbose]
+.RB [ \-A | \-\-autobackup
+.RI { y | n }]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-t | \-\-test ]
+.RB [ \-v | \-\-verbose ]
 .IR OldVolumeGroup { Path | Name | UUID }
 .IR NewVolumeGroup { Path | Name }
 .SH DESCRIPTION
 vgrename renames an existing (see
-.B vgcreate(8)
-volume group from
+.BR vgcreate (8))
+volume group from
 .IR OldVolumeGroup { Name | Path | UUID }
 to
 .IR NewVolumeGroup { Name | Path }.
-.SH OPTIONS
-See \fBlvm\fP for common options.
-.SH Examples
-"vgrename /dev/vg02 /dev/my_volume_group" renames existing
-volume group "vg02" to "my_volume_group".
-.TP
-"vgrename vg02 my_volume_group" does the same.
-.TP
-"vgrename Zvlifi-Ep3t-e0Ng-U42h-o0ye-KHu1-nl7Ns4 VolGroup00_tmp"
-changes the name of the Volume Group with UUID
-Zvlifi-Ep3t-e0Ng-U42h-o0ye-KHu1-nl7Ns4 to 
-"VolGroup00_tmp".
 
 All the Volume Groups visible to a system need to have different
 names.  Otherwise many LVM2 commands will refuse to run or give
@@ -41,7 +30,23 @@ not even boot correctly.  However, the two Volume Groups should have
 different UUIDs (unless the disk was cloned) so you can rename
 one of the conflicting Volume Groups with
 \fBvgrename\fP.
-.TP
+.SH OPTIONS
+See \fBlvm\fP(8) for common options.
+.SH Examples
+Renames existing volume group vg02 to my_volume_group:
+.sp
+.B vgrename /dev/vg02 /dev/my_volume_group
+
+or
+.sp
+.B vgrename vg02 my_volume_group
+
+Changes the name of the Volume Group with UUID
+.br
+Zvlifi-Ep3t-e0Ng-U42h-o0ye-KHu1-nl7Ns4 to VolGroup00_tmp:
+.sp
+.B vgrename Zvlifi-Ep3t-e0Ng-U42h-o0ye-KHu1-nl7Ns4 VolGroup00_tmp
+
 .SH SEE ALSO
 .BR lvm (8),
 .BR vgchange (8),
index a1a97dfd3c26fec302029605c4b6203b337ea611..e55589804526b26c8b4afe2af7d65097c1a66b19 100644 (file)
@@ -3,56 +3,69 @@
 vgs \- report information about volume groups
 .SH SYNOPSIS
 .B vgs
-[\-a|\-\-all]
-[\-\-aligned] [\-d|\-\-debug] [\-h|\-?|\-\-help]
-[\-\-ignorelockingfailure] [\-\-nameprefixes] [\-\-noheadings] [\-\-nosuffix]
-[\-o|\-\-options [+]Field[,Field]]
-[\-O|\-\-sort [+|-]Key1[,[+|-]Key2[,...]]]
-[\-P|\-\-partial] [\-\-rows]
-[\-\-separator Separator] [\-\-unbuffered]
-[\-\-units hHbBsSkKmMgGtTpPeE]
-[\-\-unquoted]
-[\-v|\-\-verbose] 
-[\-\-version] [VolumeGroupName [VolumeGroupName...]]
+.RB [ \-a | \-\-all ]
+.RB [ \-\-aligned ]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-\-ignorelockingfailure ]
+.RB [ \-\-nameprefixes ]
+.RB [ \-\-noheadings ]
+.RB [ \-\-nosuffix ]
+.RB [ \-o | \-\-options
+.RI [ + ] Field1 [ ,Field2 ...]]
+.RB [ \-O | \-\-sort
+.RI [ + | \- ] Key1 [ , [ + | \- ] Key2 ...]]
+.RB [ \-P | \-\-partial ]
+.RB [ \-\-rows ]
+.RB [ \-\-separator
+.IR Separator ]
+.RB [ \-\-unbuffered ]
+.RB [ \-\-units
+.IR hHbBsSkKmMgGtTpPeE ]
+.RB [ \-\-unquoted ]
+.RB [ \-v | \-\-verbose ]
+.RB [ \-\-version ]
+.RI [ VolumeGroupName
+.RI [ VolumeGroupName ...]]
 .SH DESCRIPTION
 vgs produces formatted output about volume groups.
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .TP
-.I \-\-all
+.B \-\-all
 List all volume groups.  Equivalent to not specifying any volume groups.
 .TP
-.I \-\-aligned
-Use with \-\-separator to align the output columns.
+.B \-\-aligned
+Use with \fB\-\-separator\fP to align the output columns.
 .TP
-.I \-\-nameprefixes
+.B \-\-nameprefixes
 Add an "LVM2_" prefix plus the field name to the output.  Useful
-with --noheadings to produce a list of field=value pairs that can
-be used to set environment variables (for example, in \fBudev (7)\fP rules).
+with \fB\-\-noheadings\fP to produce a list of field=value pairs that can
+be used to set environment variables (for example, in \fBudev\fP(7) rules).
 .TP
-.I \-\-noheadings
+.B \-\-noheadings
 Suppress the headings line that is normally the first line of output.
 Useful if grepping the output.
 .TP
-.I \-\-nosuffix
-Suppress the suffix on output sizes.  Use with \-\-units (except h and H)
-if processing the output.
+.B \-\-nosuffix
+Suppress the suffix on output sizes.  Use with \fB\-\-units\fP
+(except h and H) if processing the output.
 .TP
-.I \-o, \-\-options
+.BR \-o ", " \-\-options
 Comma-separated ordered list of columns.  Precede the list with '+' to append
 to the default selection of columns.
 .IP
-Use \fb-o vg_all\fP to select all volume group columns.
+Use \fB\-o vg_all\fP to select all volume group columns.
 .IP
-Use \fb-o help\fP to view the full list of columns available.
+Use \fB\-o help\fP to view the full list of columns available.
 .IP
 Column names include: vg_fmt, vg_uuid, vg_name, vg_attr, vg_size, vg_free,
 vg_sysid, vg_extent_size, vg_extent_count, vg_free_count, max_lv, max_pv,
 pv_count, lv_count, snap_count, vg_seqno, vg_tags, vg_mda_count, vg_mda_free,
 and vg_mda_size, vg_mda_used_count.
 .IP
-Any "vg_" prefixes are optional.  Columns mentioned in either \fBpvs (8)\fP 
-or \fBlvs (8)\fP can also be chosen, but columns cannot be taken from both
+Any "vg_" prefixes are optional.  Columns mentioned in either \fBpvs\fP(8)
+or \fBlvs\fP(8) can also be chosen, but columns cannot be taken from both
 at the same time.  
 .IP
 The vg_attr bits are:
@@ -72,27 +85,29 @@ Allocation policy: (c)ontiguous, c(l)ing, (n)ormal, (a)nywhere, (i)nherited
 (c)lustered
 .RE
 .TP
-.I \-O, \-\-sort
+.BR \-O ", " \-\-sort
 Comma-separated ordered list of columns to sort by.  Replaces the default
-selection. Precede any column with - for a reverse sort on that column.
+selection. Precede any column with '\fI\-\fP' for a reverse sort on that
+column.
 .TP
-.I \-\-rows
+.B \-\-rows
 Output columns as rows.
 .TP
-.I \-\-separator Separator
+.B \-\-separator \fISeparator
 String to use to separate each column.  Useful if grepping the output.
 .TP
-.I \-\-unbuffered
+.B \-\-unbuffered
 Produce output immediately without sorting or aligning the columns properly.
 .TP
-.I \-\-units hHbBsSkKmMgGtTpPeE
+.B \-\-units \fIhHbBsSkKmMgGtTpPeE
 All sizes are output in these units: (h)uman-readable, (b)ytes, (s)ectors,
 (k)ilobytes, (m)egabytes, (g)igabytes, (t)erabytes, (p)etabytes, (e)xabytes.  
 Capitalise to use multiples of 1000 (S.I.) instead of 1024.  Can also specify 
 custom units e.g. \-\-units 3M
 .TP
-.I \-\-unquoted
-When used with --nameprefixes, output values in the field=value pairs are not quoted.
+.B \-\-unquoted
+When used with \fB\-\-nameprefixes\fP, output values in the field=value
+pairs are not quoted.
 .SH SEE ALSO
 .BR lvm (8),
 .BR vgdisplay (8),
index cc46269160b4114bfb31adc1330f18d1502ce961..1cdc8e16a307652880e3c9391ad46feca63bde08 100644 (file)
@@ -3,11 +3,12 @@
 vgscan \- scan all disks for volume groups and rebuild caches
 .SH SYNOPSIS
 .B vgscan
-[\-d|\-\-debug] [\-h|\-?|\-\-help] 
-[\-\-ignorelockingfailure]
-[\-\-mknodes]
-[\-P|\-\-partial]
-[\-v|\-\-verbose]
+.RB [ \-d | \-\-debug ]
+.RB [ \-h | \-? | \-\-help ]
+.RB [ \-\-ignorelockingfailure ]
+.RB [ \-\-mknodes ]
+.RB [ \-P | \-\-partial ]
+.RB [ \-v | \-\-verbose ]
 .SH DESCRIPTION
 vgscan scans all SCSI, (E)IDE disks, multiple devices and a bunch
 of other disk devices in the system looking for LVM physical volumes
@@ -17,11 +18,15 @@ the scan to avoid a CD ROM, for example.
 In LVM2, vgscans take place automatically; but you might still need to
 run one explicitly after changing hardware.
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .TP
-.I \-\-mknodes
+.B \-\-mknodes
 Also checks the LVM special files in /dev that are needed for active 
 logical volumes and creates any missing ones and removes unused ones.
+.TP
+.B \-\-cache
+Scan devices for LVM physical volumes and volume groups and instruct
+the lvmetad daemon to update its cached state accordingly.
 .SH SEE ALSO
 .BR lvm (8),
 .BR vgcreate (8),
index 0c6ba228f857ae8c0d708277cd177f66514e18b2..bdcfe3b89e4ffdda778ae171c70343446c6dc731 100644 (file)
@@ -5,8 +5,10 @@ vgsplit \- split a volume group into two
 .B vgsplit
 .RB [ \-\-alloc
 .IR AllocationPolicy ]
-.RB [ \-A | \-\-autobackup " {" y | n }]
-.RB [ \-c | \-\-clustered " {" y | n }]
+.RB [ \-A | \-\-autobackup
+.RI { y | n }]
+.RB [ \-c | \-\-clustered
+.RI { y | n }]
 .RB [ \-d | \-\-debug ]
 .RB [ \-h | \-\-help ]
 .RB [ \-l | \-\-maxlogicalvolumes
@@ -15,35 +17,36 @@ vgsplit \- split a volume group into two
 .IR type ]
 .RB [ -p | \-\-maxphysicalvolumes
 .IR MaxPhysicalVolumes ]
-.RB [ \-\-[vg]metadatacopies ]
-.IR NumberOfCopies|unmanaged|all ]
-.RB [ \-n | \-\-name 
+.RB [ \-\- [ vg ] metadatacopies
+.IR NumberOfCopies | unmanaged | all ]
+.RB [ \-n | \-\-name
 .IR LogicalVolumeName ]
 .RB [ \-t | \-\-test ]
 .RB [ \-v | \-\-verbose ]
-SourceVolumeGroupName DestinationVolumeGroupName
-[ PhysicalVolumePath ...]
+.I SourceVolumeGroupName DestinationVolumeGroupName
+.RI [ PhysicalVolumePath ...]
 .SH DESCRIPTION
-.B vgsplit 
-moves one or more physical volumes from
-.I SourceVolumeGroupName
-into
-.I DestinationVolumeGroupName\fP.  The physical volumes moved can be
-specified either explicitly via \fIPhysicalVolumePath\fP, or implicitly by
-\fB-n\fP \fILogicalVolumeName\fP, in which case only physical volumes
+vgsplit moves one or more physical volumes from
+\fISourceVolumeGroupName\fP into \fIDestinationVolumeGroupName\fP.
+The physical volumes moved can be specified either explicitly via
+\fIPhysicalVolumePath\fP, or implicitly by \fB\-n\fP
+\fILogicalVolumeName\fP, in which case only physical volumes
 underlying the specified logical volume will be moved.
 
-If
-.I DestinationVolumeGroupName
-does not exist, a new volume group will be created.  The default attributes
-for the new volume group can be specified with \fB\-\-alloc\fR,
-\fB\-\-clustered\fR, \fB\-\-maxlogicalvolumes\fR, \fB\-\-metadatatype\fR,
-\fB\-\-maxphysicalvolumes\fR and \fB\-\-[vg]metadatacopies\fR,
-(see \fBvgcreate(8)\fR for a description of these options).  If any
+If \fIDestinationVolumeGroupName\fP does not exist, a new volume
+group will be created.  The default attributes
+for the new volume group can be specified with
+.BR \-\-alloc ,
+.BR \-\-clustered ,
+.BR \-\-maxlogicalvolumes ,
+.BR \-\-metadatatype ,
+.B \-\-maxphysicalvolumes \fRand
+.BR \-\- [ vg ] metadatacopies
+(see \fBvgcreate\fP(8) for a description of these options).  If any
 of these options are not given, default attribute(s) are taken from
-.I SourceVolumeGroupName\fP.  If a non-LVM2 metadata type (e.g. lvm1) is
-being used, you should use the -M option to specify the metadata type
-directly.
+\fISourceVolumeGroupName\fP. If a non-LVM2 metadata type (e.g. lvm1) is
+being used, you should use the \fB\-M\fP option to specify the metadata
+type directly.
 
 If
 .I DestinationVolumeGroupName
@@ -53,20 +56,20 @@ before the physical volumes are moved. Specifying any of the above default
 volume group attributes with an existing destination volume group is an error,
 and no split will occur.
 
-Logical volumes cannot be split between volume groups. \fBVgsplit(8)\fP only
+Logical volumes cannot be split between volume groups. \fBvgsplit\fP(8) only
 moves complete physical volumes: To move part of a physical volume, use
-\fBpvmove(8)\fP.  Each existing logical volume must be entirely on the physical
+\fBpvmove\fP(8).  Each existing logical volume must be entirely on the physical
 volumes forming either the source or the destination volume group.  For this
-reason, \fBvgsplit(8)\fP may fail with an error if a split would result in a
+reason, \fBvgsplit\fP(8) may fail with an error if a split would result in a
 logical volume being split across volume groups.
 
-A \fBvgsplit\fP into an existing volume group retains the existing volume group's
-value of \fPvgmetadatacopies\fP (see \fBvgcreate\fP and \fBlvm.conf\fP for further
+A vgsplit into an existing volume group retains the existing volume group's
+value of \fPvgmetadatacopies\fP (see \fBvgcreate\fP(8) and \fBlvm.conf\fP(5) for further
 explanation of \fPvgmetadatacopies\fP).  To change the value of
-\fBvgmetadatacopies\fP, use \fBvgchange\fP.
+\fBvgmetadatacopies\fP, use \fBvgchange\fP(8).
 
 .SH OPTIONS
-See \fBlvm\fP for common options.
+See \fBlvm\fP(8) for common options.
 .SH SEE ALSO
 .BR lvm (8),
 .BR vgcreate (8),
diff --git a/packaging/device-mapper.changes b/packaging/device-mapper.changes
deleted file mode 100644 (file)
index 2ebfe64..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-* Wed Jan 05 2011 Paolo Capriotti <paolo.capriotti@collabora.co.uk> - 1.02.60
-- Update to latest upstream version (fixes BMC#12710)
-- Build from LVM2 source.
-- Remove obsolete patch.
-
-* Thu Dec 25 2008 Arjan van de Ven <arjan@linux.intel.com> 1.02.28
-- Fix Source: to be a resolvable URL
-
-* Tue Dec 09 2008 Yi Yang <yi.y.yang@intel.com> 1.02.28
-- Upgrade to 1.02.28
-- Fixed corrupt primary.xml.gz introduced by libdevmapper.pc
-
-* Sun Nov 02 2008 Anas Nashif <anas.nashif@intel.com> 1.02.24
-- fixed file list
diff --git a/packaging/device-mapper.spec b/packaging/device-mapper.spec
deleted file mode 100644 (file)
index 46f95e9..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-%define device_mapper_version 1.02.28
-%define lvm2_version 2.02.79
-
-# Do not reset Release to 1 unless both lvm2 and device-mapper 
-# versions are increased together.
-
-Name: device-mapper
-Summary: Device mapper utility
-Version: %{device_mapper_version}
-Release: 1
-License: GPLv2
-Source0: ftp://sources.redhat.com/pub/lvm2/LVM2.%{lvm2_version}.tgz
-Group: System/Base
-URL: http://sources.redhat.com/dm
-Requires: device-mapper-libs = %{device_mapper_version}-%{release}
-
-%description -n device-mapper
-This package contains the supporting userspace utility, dmsetup,
-for the kernel device-mapper.
-
-%package -n device-mapper-devel
-Summary: Development libraries and headers for device-mapper
-Version: %{device_mapper_version}
-Release: %{release}
-License: LGPLv2.1
-Group: Development/Libraries
-Requires: device-mapper = %{device_mapper_version}-%{release}
-Requires: device-mapper-libs = %{device_mapper_version}-%{release}
-
-%description -n device-mapper-devel
-This package contains files needed to develop applications that use
-the device-mapper libraries.
-
-%package -n device-mapper-libs
-Summary: Device-mapper shared library
-Version: %{device_mapper_version}
-Release: %{release}
-License: LGPLv2.1
-Group: System/Libraries
-Obsoletes: device-mapper < 1.02.17-6
-
-%description -n device-mapper-libs
-This package contains the device-mapper shared library, libdevmapper.
-
-%prep
-%setup -q -n LVM2.%{lvm2_version}
-
-%build
-%define _exec_prefix ""
-%configure --with-user= --with-group= --with-device-uid=0 --with-device-gid=6 --with-device-mode=0660 --enable-pkgconfig
-%define _exec_prefix /
-make device-mapper
-
-%install
-rm -rf $RPM_BUILD_ROOT
-make install_device-mapper DESTDIR=$RPM_BUILD_ROOT usrlibdir=$RPM_BUILD_ROOT/usr/%{_lib}
-sed -i 's/ (.*)//g' $RPM_BUILD_ROOT%{_libdir}/pkgconfig/*.pc
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
-%post -n device-mapper-libs -p /sbin/ldconfig
-
-%postun -n device-mapper-libs -p /sbin/ldconfig
-
-%files
-%defattr(-,root,root,-)
-%doc COPYING COPYING.LIB INSTALL README VERSION_DM WHATS_NEW_DM
-%attr(755,root,root) %{_sbindir}/dmsetup
-%{_mandir}/man8/dmsetup.8.gz
-
-%files -n device-mapper-devel
-%defattr(-,root,root,-)
-%attr(755,root,root) /%{_libdir}/libdevmapper.so
-%{_includedir}/libdevmapper.h
-%{_libdir}/pkgconfig/*.pc
-
-%files -n device-mapper-libs
-%attr(755,root,root) /%{_libdir}/libdevmapper.so.*
-
-
diff --git a/python/Makefile.in b/python/Makefile.in
new file mode 100644 (file)
index 0000000..1fead22
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2011-2012 Red Hat, Inc.
+#
+# This file is part of LVM2.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU Lesser General Public License v.2.1.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = @top_builddir@
+
+python_bindings: .liblvm_built
+
+.liblvm_built: liblvm_python.c
+       $(PYTHON) setup.py build
+       touch $@
+
+liblvm_python.c:
+       $(LN_S) $(srcdir)/liblvm.c $@
+
+include $(top_builddir)/make.tmpl
+
+install_python_bindings: python_bindings
+       $(PYTHON) setup.py install --skip-build --root $(rootdir)
+
+install_lvm2: install_python_bindings
+
+install: install_lvm2
+
+CLEAN_TARGETS += .liblvm_built liblvm_python.c
+
+DISTCLEAN_DIRS += build
+DISTCLEAN_TARGETS += setup.py
diff --git a/python/example.py b/python/example.py
new file mode 100644 (file)
index 0000000..67bb7e4
--- /dev/null
@@ -0,0 +1,125 @@
+#
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+#-----------------------------
+# Python example code:
+#-----------------------------
+
+import lvm
+
+# Note: This example will create a logical unit, tag it and
+#      delete it, don't run this on production box!
+
+#Dump information about PV
+def print_pv(pv):
+    print 'PV name: ', pv.getName(), ' ID: ', pv.getUuid(), 'Size: ', pv.getSize()
+
+
+#Dump some information about a specific volume group
+def print_vg(h, vg_name):
+    #Open read only
+    vg = h.vgOpen(vg_name, 'r')
+
+    print 'Volume group:', vg_name, 'Size: ', vg.getSize()
+
+    #Retrieve a list of Physical volumes for this volume group
+    pv_list = vg.listPVs()
+
+    #Print out the physical volumes
+    for p in pv_list:
+        print_pv(p)
+
+    #Get a list of logical volumes in this volume group
+    lv_list = vg.listLVs()
+    if len(lv_list):
+        for l in lv_list:
+            print 'LV name: ', l.getName(), ' ID: ', l.getUuid()
+    else:
+        print 'No logical volumes present!'
+
+    vg.close()
+
+#Returns the name of a vg with space available
+def find_vg_with_free_space(h):
+    free_space = 0
+    rc = None
+
+    vg_names = l.listVgNames()
+    for v in vg_names:
+        vg = h.vgOpen(v, 'r')
+        c_free = vg.getFreeSize()
+        if c_free > free_space:
+            free_space = c_free
+            rc = v
+        vg.close()
+
+    return rc
+
+#Walk through the volume groups and fine one with space in which we can
+#create a new logical volume
+def create_delete_logical_volume(h):
+    vg_name = find_vg_with_free_space(h)
+
+    print 'Using volume group ', vg_name, ' for example'
+
+    if vg_name:
+        vg = h.vgOpen(vg_name, 'w')
+        lv = vg.createLvLinear('python_lvm_ok_to_delete', vg.getFreeSize())
+
+        if lv:
+            print 'New lv, id= ', lv.getUuid()
+
+            #Create a tag
+            lv.addTag('Demo_tag')
+
+            #Get the tags
+            tags = lv.getTags()
+            for t in tags:
+                #Remove tag
+                lv.removeTag(t)
+
+            #Try to rename
+            lv.rename("python_lvm_ok_to_be_removed_shortly")
+            print 'LV name= ', lv.getName()
+
+            lv.deactivate()
+            lv.remove()
+
+        vg.close()
+    else:
+        print 'No free space available to create demo lv!'
+
+if __name__ == '__main__':
+    #Create a new LVM instance
+    l = lvm.Liblvm()
+
+    #What version
+    print 'lvm version=', l.getVersion()
+
+    #Get a list of volume group names
+    vg_names = l.listVgNames()
+
+    #For each volume group display some information about each of them
+    for vg_i in vg_names:
+        print_vg(l, vg_i)
+
+    #Demo creating a logical volume
+    create_delete_logical_volume(l)
+
+    #Close
+    l.close()
diff --git a/python/liblvm.c b/python/liblvm.c
new file mode 100644 (file)
index 0000000..cbfa170
--- /dev/null
@@ -0,0 +1,1711 @@
+/*
+ * Liblvm -- Python interface to LVM2 API.
+ *
+ * Copyright (C) 2010, 2012 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Lars Sjostrom (lars sjostrom redhat com)
+ *         Andy Grover (agrover redhat com)
+ *         Tony Asleson (tasleson redhat com)
+ */
+
+#include <Python.h>
+#include "lvm2app.h"
+
+typedef struct {
+       PyObject_HEAD
+       lvm_t    libh;              /* lvm lib handle */
+} lvmobject;
+
+typedef struct {
+       PyObject_HEAD
+       vg_t      vg;               /* vg handle */
+       lvmobject *lvm_obj;
+} vgobject;
+
+typedef struct {
+       PyObject_HEAD
+       lv_t      lv;               /* lv handle */
+       lvmobject *lvm_obj;
+} lvobject;
+
+typedef struct {
+       PyObject_HEAD
+       pv_t      pv;               /* pv handle */
+       lvmobject *lvm_obj;
+} pvobject;
+
+typedef struct {
+       PyObject_HEAD
+       lvseg_t    lv_seg;            /* lv segment handle */
+       lvmobject *lvm_obj;
+} lvsegobject;
+
+typedef struct {
+       PyObject_HEAD
+       pvseg_t    pv_seg;            /* pv segment handle */
+       lvmobject *lvm_obj;
+} pvsegobject;
+
+static PyTypeObject LibLVMvgType;
+static PyTypeObject LibLVMlvType;
+static PyTypeObject LibLVMpvType;
+static PyTypeObject LibLVMlvsegType;
+static PyTypeObject LibLVMpvsegType;
+
+static PyObject *LibLVMError;
+
+
+/* ----------------------------------------------------------------------
+ * LVM object initialization/deallocation
+ */
+
+static int
+liblvm_init(lvmobject *self, PyObject *arg)
+{
+       char *systemdir = NULL;
+
+       if (!PyArg_ParseTuple(arg, "|s", &systemdir))
+               return -1;
+
+       self->libh = lvm_init(systemdir);
+       if (lvm_errno(self->libh)) {
+               PyErr_SetFromErrno(PyExc_OSError);
+               return -1;
+       }
+
+       return 0;
+}
+
+static void
+liblvm_dealloc(lvmobject *self)
+{
+       /* if already closed, don't reclose it */
+       if (self->libh != NULL){
+               lvm_quit(self->libh);
+       }
+
+       PyObject_Del(self);
+}
+
+#define LVM_VALID(lvmobject)                                           \
+       do {                                                            \
+               if (!lvmobject->libh) {                                 \
+                       PyErr_SetString(PyExc_UnboundLocalError, "LVM object invalid"); \
+                       return NULL;                                    \
+               }                                                       \
+       } while (0)
+
+static PyObject *
+liblvm_get_last_error(lvmobject *self)
+{
+       PyObject *info;
+
+       LVM_VALID(self);
+
+       if((info = PyTuple_New(2)) == NULL)
+               return NULL;
+
+       PyTuple_SetItem(info, 0, PyInt_FromLong((long) lvm_errno(self->libh)));
+       PyTuple_SetItem(info, 1, PyString_FromString(lvm_errmsg(self->libh)));
+
+       return info;
+}
+
+static PyObject *
+liblvm_library_get_version(lvmobject *self)
+{
+       LVM_VALID(self);
+
+       return Py_BuildValue("s", lvm_library_get_version());
+}
+
+
+static PyObject *
+liblvm_close(lvmobject *self)
+{
+       LVM_VALID(self);
+
+       /* if already closed, don't reclose it */
+       if (self->libh != NULL)
+               lvm_quit(self->libh);
+
+       self->libh = NULL;
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *
+liblvm_lvm_list_vg_names(lvmobject *self)
+{
+       struct dm_list *vgnames;
+       struct lvm_str_list *strl;
+       PyObject * pytuple;
+       int i = 0;
+
+       LVM_VALID(self);
+
+       vgnames = lvm_list_vg_names(self->libh);
+       if (!vgnames) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self));
+               return NULL;
+       }
+
+       pytuple = PyTuple_New(dm_list_size(vgnames));
+       if (!pytuple)
+               return NULL;
+
+       dm_list_iterate_items(strl, vgnames) {
+               PyTuple_SET_ITEM(pytuple, i, PyString_FromString(strl->str));
+               i++;
+       }
+
+       return pytuple;
+}
+
+static PyObject *
+liblvm_lvm_list_vg_uuids(lvmobject *self)
+{
+       struct dm_list *uuids;
+       struct lvm_str_list *strl;
+       PyObject * pytuple;
+       int i = 0;
+
+       LVM_VALID(self);
+
+       uuids = lvm_list_vg_uuids(self->libh);
+       if (!uuids) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self));
+               return NULL;
+       }
+
+       pytuple = PyTuple_New(dm_list_size(uuids));
+       if (!pytuple)
+               return NULL;
+
+       dm_list_iterate_items(strl, uuids) {
+               PyTuple_SET_ITEM(pytuple, i, PyString_FromString(strl->str));
+               i++;
+       }
+
+       return pytuple;
+}
+
+static PyObject *
+liblvm_lvm_percent_to_float(lvmobject *self, PyObject *arg)
+{
+       double converted;
+       int percent;
+
+       LVM_VALID(self);
+
+       if (!PyArg_ParseTuple(arg, "i", &percent))
+               return NULL;
+
+       converted = lvm_percent_to_float(percent);
+       return Py_BuildValue("d", converted);
+}
+
+static PyObject *
+liblvm_lvm_vgname_from_pvid(lvmobject *self, PyObject *arg)
+{
+       const char *pvid;
+       const char *vgname;
+
+       LVM_VALID(self);
+
+       if (!PyArg_ParseTuple(arg, "s", &pvid))
+               return NULL;
+
+       if((vgname = lvm_vgname_from_pvid(self->libh, pvid)) == NULL) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self));
+               return NULL;
+       }
+
+       return Py_BuildValue("s", vgname);
+}
+
+static PyObject *
+liblvm_lvm_vgname_from_device(lvmobject *self, PyObject *arg)
+{
+       const char *device;
+       const char *vgname;
+
+       LVM_VALID(self);
+
+       if (!PyArg_ParseTuple(arg, "s", &device))
+               return NULL;
+
+       if((vgname = lvm_vgname_from_device(self->libh, device)) == NULL) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self));
+               return NULL;
+       }
+
+       return Py_BuildValue("s", vgname);
+}
+
+
+static PyObject *
+liblvm_lvm_config_find_bool(lvmobject *self, PyObject *arg)
+{
+       const char *config;
+       int rval;
+       PyObject *rc;
+
+       LVM_VALID(self);
+
+       if (!PyArg_ParseTuple(arg, "s", &config))
+               return NULL;
+
+       if ((rval = lvm_config_find_bool(self->libh, config, -10)) == -10) {
+               /* Retrieving error information yields no error in this case */
+               PyErr_Format(PyExc_ValueError, "config path not found");
+               return NULL;
+       }
+
+       rc = (rval) ? Py_True: Py_False;
+
+       Py_INCREF(rc);
+       return rc;
+}
+
+static PyObject *
+liblvm_lvm_config_reload(lvmobject *self)
+{
+       int rval;
+
+       LVM_VALID(self);
+
+       if((rval = lvm_config_reload(self->libh)) == -1) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self));
+               return NULL;
+       }
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+
+static PyObject *
+liblvm_lvm_scan(lvmobject *self)
+{
+       int rval;
+
+       LVM_VALID(self);
+
+       if((rval = lvm_scan(self->libh)) == -1) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self));
+               return NULL;
+       }
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *
+liblvm_lvm_config_override(lvmobject *self, PyObject *arg)
+{
+       const char *config;
+       int rval;
+
+       LVM_VALID(self);
+
+       if (!PyArg_ParseTuple(arg, "s", &config))
+               return NULL;
+
+       if ((rval = lvm_config_override(self->libh, config)) == -1) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self));
+               return NULL;
+       }
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+/* ----------------------------------------------------------------------
+ * VG object initialization/deallocation
+ */
+
+
+static PyObject *
+liblvm_lvm_vg_open(lvmobject *lvm, PyObject *args)
+{
+       const char *vgname;
+       const char *mode = NULL;
+
+       vgobject *self;
+
+       LVM_VALID(lvm);
+
+       if (!PyArg_ParseTuple(args, "s|s", &vgname, &mode)) {
+               return NULL;
+       }
+
+       if (mode == NULL)
+               mode = "r";
+
+       if ((self = PyObject_New(vgobject, &LibLVMvgType)) == NULL)
+               return NULL;
+
+       if ((self->vg = lvm_vg_open(lvm->libh, vgname, mode, 0))== NULL) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(lvm));
+               Py_DECREF(self);
+               return NULL;
+       }
+       self->lvm_obj = lvm;
+
+       return (PyObject *)self;
+}
+
+static PyObject *
+liblvm_lvm_vg_create(lvmobject *lvm, PyObject *args)
+{
+       const char *vgname;
+       vgobject *self;
+
+       LVM_VALID(lvm);
+
+       if (!PyArg_ParseTuple(args, "s", &vgname)) {
+               return NULL;
+       }
+
+       if ((self = PyObject_New(vgobject, &LibLVMvgType)) == NULL)
+               return NULL;
+
+       if ((self->vg = lvm_vg_create(lvm->libh, vgname))== NULL) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(lvm));
+               Py_DECREF(self);
+               return NULL;
+       }
+       self->lvm_obj = lvm;
+
+       return (PyObject *)self;
+}
+
+static void
+liblvm_vg_dealloc(vgobject *self)
+{
+       /* if already closed, don't reclose it */
+       if (self->vg != NULL)
+               lvm_vg_close(self->vg);
+       PyObject_Del(self);
+}
+
+/* VG Methods */
+
+#define VG_VALID(vgobject)                                             \
+       do {                                                            \
+               if (!vgobject->vg) {                                    \
+                       PyErr_SetString(PyExc_UnboundLocalError, "VG object invalid"); \
+                       return NULL;                                    \
+               }                                                       \
+       } while (0)
+
+static PyObject *
+liblvm_lvm_vg_close(vgobject *self)
+{
+       /* if already closed, don't reclose it */
+       if (self->vg != NULL)
+               lvm_vg_close(self->vg);
+
+       self->vg = NULL;
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *
+liblvm_lvm_vg_get_name(vgobject *self)
+{
+       VG_VALID(self);
+
+       return Py_BuildValue("s", lvm_vg_get_name(self->vg));
+}
+
+
+static PyObject *
+liblvm_lvm_vg_get_uuid(vgobject *self)
+{
+       VG_VALID(self);
+
+       return Py_BuildValue("s", lvm_vg_get_uuid(self->vg));
+}
+
+static PyObject *
+liblvm_lvm_vg_remove(vgobject *self)
+{
+       int rval;
+
+       VG_VALID(self);
+
+       if ((rval = lvm_vg_remove(self->vg)) == -1)
+               goto error;
+
+       if (lvm_vg_write(self->vg) == -1)
+               goto error;
+
+       self->vg = NULL;
+
+       Py_INCREF(Py_None);
+       return Py_None;
+
+error:
+       PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj));
+       return NULL;
+}
+
+static PyObject *
+liblvm_lvm_vg_extend(vgobject *self, PyObject *args)
+{
+       const char *device;
+       int rval;
+
+       VG_VALID(self);
+
+       if (!PyArg_ParseTuple(args, "s", &device)) {
+               return NULL;
+       }
+
+       if ((rval = lvm_vg_extend(self->vg, device)) == -1)
+               goto error;
+
+       if (lvm_vg_write(self->vg) == -1)
+               goto error;
+
+       Py_INCREF(Py_None);
+       return Py_None;
+
+error:
+       PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj));
+       return NULL;
+}
+
+static PyObject *
+liblvm_lvm_vg_reduce(vgobject *self, PyObject *args)
+{
+       const char *device;
+       int rval;
+
+       VG_VALID(self);
+
+       if (!PyArg_ParseTuple(args, "s", &device)) {
+               return NULL;
+       }
+
+       if ((rval = lvm_vg_reduce(self->vg, device)) == -1)
+               goto error;
+
+       if (lvm_vg_write(self->vg) == -1)
+               goto error;
+
+       Py_INCREF(Py_None);
+       return Py_None;
+
+error:
+       PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj));
+       return NULL;
+}
+
+static PyObject *
+liblvm_lvm_vg_add_tag(vgobject *self, PyObject *args)
+{
+       const char *tag;
+       int rval;
+
+       VG_VALID(self);
+
+       if (!PyArg_ParseTuple(args, "s", &tag)) {
+               return NULL;
+       }
+       if ((rval = lvm_vg_add_tag(self->vg, tag)) == -1)
+               goto error;
+
+       if (lvm_vg_write(self->vg) == -1)
+               goto error;
+
+       return Py_BuildValue("i", rval);
+
+error:
+       PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj));
+       return NULL;
+}
+
+static PyObject *
+liblvm_lvm_vg_remove_tag(vgobject *self, PyObject *args)
+{
+       const char *tag;
+       int rval;
+
+       VG_VALID(self);
+
+       if (!PyArg_ParseTuple(args, "s", &tag)) {
+               return NULL;
+       }
+
+       if ((rval = lvm_vg_remove_tag(self->vg, tag)) == -1)
+               goto error;
+
+       if (lvm_vg_write(self->vg) == -1)
+               goto error;
+
+       Py_INCREF(Py_None);
+       return Py_None;
+
+error:
+       PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj));
+       return NULL;
+
+}
+
+static PyObject *
+liblvm_lvm_vg_is_clustered(vgobject *self)
+{
+       PyObject *rval;
+
+       VG_VALID(self);
+
+       rval = ( lvm_vg_is_clustered(self->vg) == 1) ? Py_True : Py_False;
+
+       Py_INCREF(rval);
+       return rval;
+}
+
+static PyObject *
+liblvm_lvm_vg_is_exported(vgobject *self)
+{
+       PyObject *rval;
+
+       VG_VALID(self);
+
+       rval = ( lvm_vg_is_exported(self->vg) == 1) ? Py_True : Py_False;
+
+       Py_INCREF(rval);
+       return rval;
+}
+
+static PyObject *
+liblvm_lvm_vg_is_partial(vgobject *self)
+{
+       PyObject *rval;
+
+       VG_VALID(self);
+
+       rval = ( lvm_vg_is_partial(self->vg) == 1) ? Py_True : Py_False;
+
+       Py_INCREF(rval);
+       return rval;
+}
+
+static PyObject *
+liblvm_lvm_vg_get_seqno(vgobject *self)
+{
+       VG_VALID(self);
+
+       return Py_BuildValue("l", lvm_vg_get_seqno(self->vg));
+}
+
+static PyObject *
+liblvm_lvm_vg_get_size(vgobject *self)
+{
+       VG_VALID(self);
+
+       return Py_BuildValue("l", lvm_vg_get_size(self->vg));
+}
+
+static PyObject *
+liblvm_lvm_vg_get_free_size(vgobject *self)
+{
+       VG_VALID(self);
+
+       return Py_BuildValue("l", lvm_vg_get_free_size(self->vg));
+}
+
+static PyObject *
+liblvm_lvm_vg_get_extent_size(vgobject *self)
+{
+       VG_VALID(self);
+
+       return Py_BuildValue("l", lvm_vg_get_extent_size(self->vg));
+}
+
+static PyObject *
+liblvm_lvm_vg_get_extent_count(vgobject *self)
+{
+       VG_VALID(self);
+
+       return Py_BuildValue("l", lvm_vg_get_extent_count(self->vg));
+}
+
+static PyObject *
+liblvm_lvm_vg_get_free_extent_count(vgobject *self)
+{
+       VG_VALID(self);
+
+       return Py_BuildValue("l", lvm_vg_get_free_extent_count(self->vg));
+}
+
+/* Builds a python tuple ([string|number], bool) from a struct lvm_property_value */
+static PyObject *
+get_property(lvmobject *h, struct lvm_property_value *prop)
+{
+       PyObject *pytuple;
+       PyObject *setable;
+
+       if( !prop->is_valid ) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(h));
+               return NULL;
+       }
+
+       pytuple = PyTuple_New(2);
+       if (!pytuple)
+               return NULL;
+
+       if( prop->is_integer ) {
+               PyTuple_SET_ITEM(pytuple, 0, Py_BuildValue("K", prop->value.integer));
+       } else {
+               PyTuple_SET_ITEM(pytuple, 0, PyString_FromString(prop->value.string));
+       }
+
+       if (prop->is_settable) {
+               setable = Py_True;
+       } else {
+               setable = Py_False;
+       }
+
+       Py_INCREF(setable);
+       PyTuple_SET_ITEM(pytuple, 1, setable);
+       return pytuple;
+}
+
+/* This will return a tuple of (value, bool) with the value being a string or
+   integer and bool indicating if property is settable */
+static PyObject *
+liblvm_lvm_vg_get_property(vgobject *self,  PyObject *args)
+{
+       const char *name;
+       struct lvm_property_value prop_value;
+
+       VG_VALID(self);
+
+       if (!PyArg_ParseTuple(args, "s", &name))
+               return NULL;
+
+       prop_value = lvm_vg_get_property(self->vg, name);
+       return get_property(self->lvm_obj, &prop_value);
+}
+
+static PyObject *
+liblvm_lvm_vg_set_property(vgobject *self,  PyObject *args)
+{
+       const char *property_name = NULL;
+       PyObject *variant_type_arg = NULL;
+       struct lvm_property_value lvm_property;
+       char *string_value = NULL;
+
+       VG_VALID(self);
+
+       if (!PyArg_ParseTuple(args, "sO", &property_name, &variant_type_arg))
+               return NULL;
+
+       lvm_property = lvm_vg_get_property(self->vg, property_name);
+
+       if( !lvm_property.is_valid ) {
+               goto lvmerror;
+       }
+
+       if(PyObject_IsInstance(variant_type_arg, (PyObject*)&PyString_Type)) {
+
+               if (!lvm_property.is_string) {
+                       PyErr_Format(PyExc_ValueError, "Property requires string value");
+                       goto bail;
+               }
+
+               /* Based on cursory code inspection this path may cause a memory
+                  leak when calling into set_property, need to verify*/
+               string_value = strdup(PyString_AsString(variant_type_arg));
+               lvm_property.value.string = string_value;
+               if(!lvm_property.value.string) {
+                       PyErr_NoMemory();
+                       goto bail;
+               }
+
+       } else {
+
+               if (!lvm_property.is_integer) {
+                       PyErr_Format(PyExc_ValueError, "Property requires numeric value");
+                       goto bail;
+               }
+
+               if(PyObject_IsInstance(variant_type_arg, (PyObject*)&PyInt_Type)) {
+                       int temp_py_int = PyInt_AsLong(variant_type_arg);
+
+                       /* -1 could be valid, need to see if an exception was gen. */
+                       if( -1 == temp_py_int ) {
+                               if( PyErr_Occurred() ) {
+                                       goto bail;
+                               }
+                       }
+
+                       if (temp_py_int < 0) {
+                               PyErr_Format(PyExc_ValueError, "Positive integers only!");
+                               goto bail;
+                       }
+
+                       lvm_property.value.integer = temp_py_int;
+               } else if(PyObject_IsInstance(variant_type_arg, (PyObject*)&PyLong_Type)){
+                       /* This will fail on negative numbers */
+                       unsigned long long temp_py_long = PyLong_AsUnsignedLongLong(variant_type_arg);
+                       if( (unsigned long long)-1 == temp_py_long ) {
+                               goto bail;
+                       }
+
+                       lvm_property.value.integer = temp_py_long;
+               } else {
+                       PyErr_Format(PyExc_ValueError, "supported value types are numeric and string");
+                       goto bail;
+               }
+       }
+
+       if( -1 == lvm_vg_set_property(self->vg, property_name, &lvm_property) ) {
+               goto lvmerror;
+       }
+
+       if( -1 == lvm_vg_write(self->vg)) {
+               goto lvmerror;
+       }
+
+       Py_DECREF(variant_type_arg);
+       Py_INCREF(Py_None);
+       return Py_None;
+
+lvmerror:
+       PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj));
+bail:
+       free(string_value);
+       if( variant_type_arg ) {
+               Py_DECREF(variant_type_arg);
+               variant_type_arg = NULL;
+       }
+       return NULL;
+}
+
+static PyObject *
+liblvm_lvm_vg_get_pv_count(vgobject *self)
+{
+       VG_VALID(self);
+
+       return Py_BuildValue("l", lvm_vg_get_pv_count(self->vg));
+}
+
+static PyObject *
+liblvm_lvm_vg_get_max_pv(vgobject *self)
+{
+       VG_VALID(self);
+
+       return Py_BuildValue("l", lvm_vg_get_max_pv(self->vg));
+}
+
+static PyObject *
+liblvm_lvm_vg_get_max_lv(vgobject *self)
+{
+       VG_VALID(self);
+
+       return Py_BuildValue("l", lvm_vg_get_max_lv(self->vg));
+}
+
+static PyObject *
+liblvm_lvm_vg_set_extent_size(vgobject *self, PyObject *args)
+{
+       uint32_t new_size;
+       int rval;
+
+       VG_VALID(self);
+
+       if (!PyArg_ParseTuple(args, "l", &new_size)) {
+               return NULL;
+       }
+
+       if ((rval = lvm_vg_set_extent_size(self->vg, new_size)) == -1) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj));
+               return NULL;
+       }
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *
+liblvm_lvm_vg_list_lvs(vgobject *vg)
+{
+       struct dm_list *lvs;
+       struct lvm_lv_list *lvl;
+       PyObject * pytuple;
+       lvobject * self;
+       int i = 0;
+
+       VG_VALID(vg);
+
+       /* unlike other LVM api calls, if there are no results, we get NULL */
+       lvs = lvm_vg_list_lvs(vg->vg);
+       if (!lvs)
+               return Py_BuildValue("()");
+
+       pytuple = PyTuple_New(dm_list_size(lvs));
+       if (!pytuple)
+               return NULL;
+
+       dm_list_iterate_items(lvl, lvs) {
+               /* Create and initialize the object */
+               self = PyObject_New(lvobject, &LibLVMlvType);
+               if (!self) {
+                       Py_DECREF(pytuple);
+                       return NULL;
+               }
+
+               self->lv = lvl->lv;
+               self->lvm_obj = vg->lvm_obj;
+               PyTuple_SET_ITEM(pytuple, i, (PyObject *) self);
+               i++;
+       }
+
+       return pytuple;
+}
+
+static PyObject *
+liblvm_lvm_vg_get_tags(vgobject *self)
+{
+       struct dm_list *tags;
+       struct lvm_str_list *strl;
+       PyObject * pytuple;
+       int i = 0;
+
+       VG_VALID(self);
+
+       tags = lvm_vg_get_tags(self->vg);
+       if (!tags) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj));
+               return NULL;
+       }
+
+       pytuple = PyTuple_New(dm_list_size(tags));
+       if (!pytuple)
+               return NULL;
+
+       dm_list_iterate_items(strl, tags) {
+               PyTuple_SET_ITEM(pytuple, i, PyString_FromString(strl->str));
+               i++;
+       }
+
+       return pytuple;
+}
+
+static PyObject *
+liblvm_lvm_vg_create_lv_linear(vgobject *vg, PyObject *args)
+{
+       const char *vgname;
+       uint64_t size;
+       lvobject *self;
+
+       VG_VALID(vg);
+
+       if (!PyArg_ParseTuple(args, "sl", &vgname, &size)) {
+               return NULL;
+       }
+
+       if ((self = PyObject_New(lvobject, &LibLVMlvType)) == NULL)
+               return NULL;
+
+       if ((self->lv = lvm_vg_create_lv_linear(vg->vg, vgname, size))== NULL) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(vg->lvm_obj));
+               Py_DECREF(self);
+               return NULL;
+       }
+       self->lvm_obj = vg->lvm_obj;
+
+       return (PyObject *)self;
+}
+
+static void
+liblvm_lv_dealloc(lvobject *self)
+{
+       PyObject_Del(self);
+}
+
+static PyObject *
+liblvm_lvm_vg_list_pvs(vgobject *vg)
+{
+       struct dm_list *pvs;
+       struct lvm_pv_list *pvl;
+       PyObject * pytuple;
+       pvobject * self;
+       int i = 0;
+
+       VG_VALID(vg);
+
+       /* unlike other LVM api calls, if there are no results, we get NULL */
+       pvs = lvm_vg_list_pvs(vg->vg);
+       if (!pvs)
+               return Py_BuildValue("()");
+
+       pytuple = PyTuple_New(dm_list_size(pvs));
+       if (!pytuple)
+               return NULL;
+
+       dm_list_iterate_items(pvl, pvs) {
+               /* Create and initialize the object */
+               self = PyObject_New(pvobject, &LibLVMpvType);
+               if (!self) {
+                       Py_DECREF(pytuple);
+                       return NULL;
+               }
+
+               self->pv = pvl->pv;
+               self->lvm_obj = vg->lvm_obj;
+               PyTuple_SET_ITEM(pytuple, i, (PyObject *) self);
+               i++;
+       }
+
+       return pytuple;
+}
+
+typedef lv_t (*lv_fetch_by_N)(vg_t vg, const char *id);
+typedef pv_t (*pv_fetch_by_N)(vg_t vg, const char *id);
+
+static PyObject *
+liblvm_lvm_lv_from_N(vgobject *self, PyObject *arg, lv_fetch_by_N method)
+{
+       const char *id;
+       lvobject *rc;
+       lv_t lv = NULL;
+
+       VG_VALID(self);
+
+       if (!PyArg_ParseTuple(arg, "s", &id))
+               return NULL;
+
+       lv = method(self->vg, id);
+       if( !lv ) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj));
+               return NULL;
+       }
+
+       rc = PyObject_New(lvobject, &LibLVMlvType);
+       if( !rc ) {
+               return NULL;
+       }
+
+       rc->lv = lv;
+       rc->lvm_obj = self->lvm_obj;
+       return (PyObject *)rc;
+}
+
+static PyObject *
+liblvm_lvm_lv_from_name(vgobject *self, PyObject *arg)
+{
+       return liblvm_lvm_lv_from_N(self, arg, lvm_lv_from_name);
+}
+
+static PyObject *
+liblvm_lvm_lv_from_uuid(vgobject *self, PyObject *arg)
+{
+       return liblvm_lvm_lv_from_N(self, arg, lvm_lv_from_uuid);
+}
+
+static PyObject *
+liblvm_lvm_pv_from_N(vgobject *self, PyObject *arg, pv_fetch_by_N method)
+{
+       const char *id;
+       pvobject *rc;
+       pv_t pv = NULL;
+
+       VG_VALID(self);
+
+       if (!PyArg_ParseTuple(arg, "s", &id))
+               return NULL;
+
+       pv = method(self->vg, id);
+       if( !pv ) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj));
+               return NULL;
+       }
+
+       rc = PyObject_New(pvobject, &LibLVMpvType);
+       if( !rc ) {
+               return NULL;
+       }
+
+       rc->pv = pv;
+       rc->lvm_obj = self->lvm_obj;
+       return (PyObject *)rc;
+}
+
+static PyObject *
+liblvm_lvm_pv_from_name(vgobject *self, PyObject *arg)
+{
+       return liblvm_lvm_pv_from_N(self, arg, lvm_pv_from_name);
+}
+
+static PyObject *
+liblvm_lvm_pv_from_uuid(vgobject *self, PyObject *arg)
+{
+       return liblvm_lvm_pv_from_N(self, arg, lvm_pv_from_uuid);
+}
+
+static void
+liblvm_pv_dealloc(pvobject *self)
+{
+       PyObject_Del(self);
+}
+
+/* LV Methods */
+
+#define LV_VALID(lvobject)                                             \
+       do {                                                            \
+               if (!lvobject->lv) {                                    \
+                       PyErr_SetString(PyExc_UnboundLocalError, "LV object invalid"); \
+                       return NULL;                                    \
+               }                                                       \
+       } while (0)
+
+
+static PyObject *
+liblvm_lvm_lv_get_name(lvobject *self)
+{
+       LV_VALID(self);
+
+       return Py_BuildValue("s", lvm_lv_get_name(self->lv));
+}
+
+static PyObject *
+liblvm_lvm_lv_get_uuid(lvobject *self)
+{
+       LV_VALID(self);
+
+       return Py_BuildValue("s", lvm_lv_get_uuid(self->lv));
+}
+
+static PyObject *
+liblvm_lvm_lv_activate(lvobject *self)
+{
+       int rval;
+
+       LV_VALID(self);
+
+       if ((rval = lvm_lv_activate(self->lv)) == -1) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj));
+               return NULL;
+       }
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *
+liblvm_lvm_lv_deactivate(lvobject *self)
+{
+       int rval;
+
+       LV_VALID(self);
+
+       if ((rval = lvm_lv_deactivate(self->lv)) == -1) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj));
+               return NULL;
+       }
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *
+liblvm_lvm_vg_remove_lv(lvobject *self)
+{
+       int rval;
+
+       LV_VALID(self);
+
+       if ((rval = lvm_vg_remove_lv(self->lv)) == -1) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj));
+               return NULL;
+       }
+
+       self->lv = NULL;
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+/* This will return a tuple of (value, bool) with the value being a string or
+   integer and bool indicating if property is settable */
+static PyObject *
+liblvm_lvm_lv_get_property(lvobject *self,  PyObject *args)
+{
+       const char *name;
+       struct lvm_property_value prop_value;
+
+       LV_VALID(self);
+
+       if (!PyArg_ParseTuple(args, "s", &name))
+               return NULL;
+
+       prop_value = lvm_lv_get_property(self->lv, name);
+       return get_property(self->lvm_obj, &prop_value);
+}
+
+static PyObject *
+liblvm_lvm_lv_get_size(lvobject *self)
+{
+       LV_VALID(self);
+
+       return Py_BuildValue("l", lvm_lv_get_size(self->lv));
+}
+
+static PyObject *
+liblvm_lvm_lv_is_active(lvobject *self)
+{
+       PyObject *rval;
+
+       LV_VALID(self);
+
+       rval = ( lvm_lv_is_active(self->lv) == 1) ? Py_True : Py_False;
+
+       Py_INCREF(rval);
+       return rval;
+}
+
+static PyObject *
+liblvm_lvm_lv_is_suspended(lvobject *self)
+{
+       PyObject *rval;
+
+       LV_VALID(self);
+
+       rval = ( lvm_lv_is_suspended(self->lv) == 1) ? Py_True : Py_False;
+
+       Py_INCREF(rval);
+       return rval;
+}
+
+static PyObject *
+liblvm_lvm_lv_add_tag(lvobject *self, PyObject *args)
+{
+       const char *tag;
+       int rval;
+
+       LV_VALID(self);
+
+       if (!PyArg_ParseTuple(args, "s", &tag)) {
+               return NULL;
+       }
+
+       if ((rval = lvm_lv_add_tag(self->lv, tag)) == -1) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj));
+               return NULL;
+       }
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *
+liblvm_lvm_lv_remove_tag(lvobject *self, PyObject *args)
+{
+       const char *tag;
+       int rval;
+
+       LV_VALID(self);
+
+       if (!PyArg_ParseTuple(args, "s", &tag)) {
+               return NULL;
+       }
+
+       if ((rval = lvm_lv_remove_tag(self->lv, tag)) == -1) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj));
+               return NULL;
+       }
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *
+liblvm_lvm_lv_get_tags(lvobject *self)
+{
+       struct dm_list *tags;
+       struct lvm_str_list *strl;
+       PyObject * pytuple;
+       int i = 0;
+
+       LV_VALID(self);
+
+       tags = lvm_lv_get_tags(self->lv);
+       if (!tags) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj));
+               return NULL;
+       }
+
+       pytuple = PyTuple_New(dm_list_size(tags));
+       if (!pytuple)
+               return NULL;
+
+       dm_list_iterate_items(strl, tags) {
+               PyTuple_SET_ITEM(pytuple, i, PyString_FromString(strl->str));
+               i++;
+       }
+
+       return pytuple;
+}
+
+static PyObject *
+liblvm_lvm_lv_rename(lvobject *self, PyObject *args)
+{
+       const char *new_name;
+       int rval;
+
+       LV_VALID(self);
+
+       if (!PyArg_ParseTuple(args, "s", &new_name))
+               return NULL;
+
+       if ((rval = lvm_lv_rename(self->lv, new_name)) == -1) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj));
+               return NULL;
+       }
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *
+liblvm_lvm_lv_resize(lvobject *self, PyObject *args)
+{
+       uint64_t new_size;
+       int rval;
+
+       LV_VALID(self);
+
+       if (!PyArg_ParseTuple(args, "l", &new_size)) {
+               return NULL;
+       }
+
+       if ((rval = lvm_lv_resize(self->lv, new_size)) == -1) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj));
+               return NULL;
+       }
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *
+liblvm_lvm_lv_list_lvsegs(lvobject *lv)
+{
+       struct dm_list  *lvsegs;
+       lvseg_list_t    *lvsegl;
+       PyObject * pytuple;
+       lvsegobject *self;
+       int i = 0;
+
+       LV_VALID(lv);
+
+       lvsegs = lvm_lv_list_lvsegs(lv->lv);
+       if(!lvsegs) {
+               return Py_BuildValue("()");
+       }
+
+       pytuple = PyTuple_New(dm_list_size(lvsegs));
+       if (!pytuple)
+               return NULL;
+
+       dm_list_iterate_items(lvsegl, lvsegs) {
+               /* Create and initialize the object */
+               self = PyObject_New(lvsegobject, &LibLVMlvsegType);
+               if (!self) {
+                       Py_DECREF(pytuple);
+                       return NULL;
+               }
+
+               self->lv_seg = lvsegl->lvseg;
+               self->lvm_obj = lv->lvm_obj;
+               PyTuple_SET_ITEM(pytuple, i, (PyObject *) self);
+               i++;
+       }
+
+       return pytuple;
+}
+
+/* PV Methods */
+
+#define PV_VALID(pvobject)                                             \
+       do {                                                            \
+               if (!pvobject->pv || !pvobject->lvm_obj) {              \
+                       PyErr_SetString(PyExc_UnboundLocalError, "PV object invalid"); \
+                       return NULL;                                    \
+               }                                                       \
+       } while (0)
+
+static PyObject *
+liblvm_lvm_pv_get_name(pvobject *self)
+{
+       return Py_BuildValue("s", lvm_pv_get_name(self->pv));
+}
+
+static PyObject *
+liblvm_lvm_pv_get_uuid(pvobject *self)
+{
+       return Py_BuildValue("s", lvm_pv_get_uuid(self->pv));
+}
+
+static PyObject *
+liblvm_lvm_pv_get_mda_count(pvobject *self)
+{
+       return Py_BuildValue("l", lvm_pv_get_mda_count(self->pv));
+}
+
+static PyObject *
+liblvm_lvm_pv_get_property(pvobject *self,  PyObject *args)
+{
+       const char *name;
+       struct lvm_property_value prop_value;
+
+       PV_VALID(self);
+
+       if (!PyArg_ParseTuple(args, "s", &name))
+               return NULL;
+
+       prop_value = lvm_pv_get_property(self->pv, name);
+       return get_property(self->lvm_obj, &prop_value);
+}
+
+static PyObject *
+liblvm_lvm_pv_get_dev_size(pvobject *self)
+{
+       return Py_BuildValue("l", lvm_pv_get_dev_size(self->pv));
+}
+
+static PyObject *
+liblvm_lvm_pv_get_size(pvobject *self)
+{
+       return Py_BuildValue("l", lvm_pv_get_size(self->pv));
+}
+
+static PyObject *
+liblvm_lvm_pv_get_free(pvobject *self)
+{
+       return Py_BuildValue("l", lvm_pv_get_free(self->pv));
+}
+
+static PyObject *
+liblvm_lvm_pv_resize(pvobject *self, PyObject *args)
+{
+       uint64_t new_size;
+       int rval;
+
+       if (!PyArg_ParseTuple(args, "l", &new_size)) {
+               return NULL;
+       }
+
+       if ((rval = lvm_pv_resize(self->pv, new_size)) == -1) {
+               PyErr_SetObject(LibLVMError, liblvm_get_last_error(self->lvm_obj));
+               return NULL;
+       }
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *
+liblvm_lvm_lv_list_pvsegs(pvobject *pv)
+{
+       struct dm_list *pvsegs;
+       pvseg_list_t *pvsegl;
+       PyObject *pytuple;
+       pvsegobject *self;
+       int i = 0;
+
+       PV_VALID(pv);
+
+       pvsegs = lvm_pv_list_pvsegs(pv->pv);
+       if(!pvsegs) {
+               return Py_BuildValue("()");
+       }
+
+       pytuple = PyTuple_New(dm_list_size(pvsegs));
+       if (!pytuple)
+               return NULL;
+
+       dm_list_iterate_items(pvsegl, pvsegs) {
+               /* Create and initialize the object */
+               self = PyObject_New(pvsegobject, &LibLVMpvsegType);
+               if (!self) {
+                       Py_DECREF(pytuple);
+                       return NULL;
+               }
+
+               self->pv_seg = pvsegl->pvseg;
+               self->lvm_obj = pv->lvm_obj;
+               PyTuple_SET_ITEM(pytuple, i, (PyObject *) self);
+               i++;
+       }
+
+       return pytuple;
+}
+
+/* LV seg methods */
+
+static void
+liblvm_lvseg_dealloc(lvsegobject *self)
+{
+       PyObject_Del(self);
+}
+
+static PyObject *
+liblvm_lvm_lvseg_get_property(lvsegobject *self,  PyObject *args)
+{
+       const char *name;
+       struct lvm_property_value prop_value;
+
+       if (!PyArg_ParseTuple(args, "s", &name))
+               return NULL;
+
+       prop_value = lvm_lvseg_get_property(self->lv_seg, name);
+       return get_property(self->lvm_obj, &prop_value);
+}
+
+/* PV seg methods */
+
+static void
+liblvm_pvseg_dealloc(pvsegobject *self)
+{
+       PyObject_Del(self);
+}
+
+static PyObject *
+liblvm_lvm_pvseg_get_property(pvsegobject *self,  PyObject *args)
+{
+       const char *name;
+       struct lvm_property_value prop_value;
+
+       if (!PyArg_ParseTuple(args, "s", &name))
+               return NULL;
+
+       prop_value = lvm_pvseg_get_property(self->pv_seg, name);
+       return get_property(self->lvm_obj, &prop_value);
+}
+
+/* ----------------------------------------------------------------------
+ * Method tables and other bureaucracy
+ */
+
+static PyMethodDef Liblvm_methods[] = {
+       /* LVM methods */
+       { "getVersion",         (PyCFunction)liblvm_library_get_version, METH_NOARGS },
+       { "vgOpen",             (PyCFunction)liblvm_lvm_vg_open, METH_VARARGS },
+       { "vgCreate",           (PyCFunction)liblvm_lvm_vg_create, METH_VARARGS },
+       { "close",              (PyCFunction)liblvm_close, METH_NOARGS },
+       { "configFindBool",     (PyCFunction)liblvm_lvm_config_find_bool, METH_VARARGS },
+       { "configReload",       (PyCFunction)liblvm_lvm_config_reload, METH_NOARGS },
+       { "configOverride",     (PyCFunction)liblvm_lvm_config_override, METH_VARARGS },
+       { "scan",               (PyCFunction)liblvm_lvm_scan, METH_NOARGS },
+       { "listVgNames",        (PyCFunction)liblvm_lvm_list_vg_names, METH_NOARGS },
+       { "listVgUuids",        (PyCFunction)liblvm_lvm_list_vg_uuids, METH_NOARGS },
+       { "percentToFloat",     (PyCFunction)liblvm_lvm_percent_to_float, METH_VARARGS },
+       { "vgNameFromPvid",     (PyCFunction)liblvm_lvm_vgname_from_pvid, METH_VARARGS },
+       { "vgNameFromDevice",   (PyCFunction)liblvm_lvm_vgname_from_device, METH_VARARGS },
+       { NULL,      NULL}         /* sentinel */
+};
+
+static PyMethodDef liblvm_vg_methods[] = {
+       /* vg methods */
+       { "getName",            (PyCFunction)liblvm_lvm_vg_get_name, METH_NOARGS },
+       { "getUuid",            (PyCFunction)liblvm_lvm_vg_get_uuid, METH_NOARGS },
+       { "close",              (PyCFunction)liblvm_lvm_vg_close, METH_NOARGS },
+       { "remove",             (PyCFunction)liblvm_lvm_vg_remove, METH_NOARGS },
+       { "extend",             (PyCFunction)liblvm_lvm_vg_extend, METH_VARARGS },
+       { "reduce",             (PyCFunction)liblvm_lvm_vg_reduce, METH_VARARGS },
+       { "addTag",             (PyCFunction)liblvm_lvm_vg_add_tag, METH_VARARGS },
+       { "removeTag",          (PyCFunction)liblvm_lvm_vg_remove_tag, METH_VARARGS },
+       { "setExtentSize",      (PyCFunction)liblvm_lvm_vg_set_extent_size, METH_VARARGS },
+       { "isClustered",        (PyCFunction)liblvm_lvm_vg_is_clustered, METH_NOARGS },
+       { "isExported",         (PyCFunction)liblvm_lvm_vg_is_exported, METH_NOARGS },
+       { "isPartial",          (PyCFunction)liblvm_lvm_vg_is_partial, METH_NOARGS },
+       { "getSeqno",           (PyCFunction)liblvm_lvm_vg_get_seqno, METH_NOARGS },
+       { "getSize",            (PyCFunction)liblvm_lvm_vg_get_size, METH_NOARGS },
+       { "getFreeSize",        (PyCFunction)liblvm_lvm_vg_get_free_size, METH_NOARGS },
+       { "getExtentSize",      (PyCFunction)liblvm_lvm_vg_get_extent_size, METH_NOARGS },
+       { "getExtentCount",     (PyCFunction)liblvm_lvm_vg_get_extent_count, METH_NOARGS },
+       { "getFreeExtentCount", (PyCFunction)liblvm_lvm_vg_get_free_extent_count, METH_NOARGS },
+       { "getProperty",        (PyCFunction)liblvm_lvm_vg_get_property, METH_VARARGS },
+       { "setProperty",        (PyCFunction)liblvm_lvm_vg_set_property, METH_VARARGS },
+       { "getPvCount",         (PyCFunction)liblvm_lvm_vg_get_pv_count, METH_NOARGS },
+       { "getMaxPv",           (PyCFunction)liblvm_lvm_vg_get_max_pv, METH_NOARGS },
+       { "getMaxLv",           (PyCFunction)liblvm_lvm_vg_get_max_lv, METH_NOARGS },
+       { "listLVs",            (PyCFunction)liblvm_lvm_vg_list_lvs, METH_NOARGS },
+       { "listPVs",            (PyCFunction)liblvm_lvm_vg_list_pvs, METH_NOARGS },
+       { "lvFromName",         (PyCFunction)liblvm_lvm_lv_from_name, METH_VARARGS },
+       { "lvFromUuid",         (PyCFunction)liblvm_lvm_lv_from_uuid, METH_VARARGS },
+       { "pvFromName",         (PyCFunction)liblvm_lvm_pv_from_name, METH_VARARGS },
+       { "pvFromUuid",         (PyCFunction)liblvm_lvm_pv_from_uuid, METH_VARARGS },
+       { "getTags",            (PyCFunction)liblvm_lvm_vg_get_tags, METH_NOARGS },
+       { "createLvLinear",     (PyCFunction)liblvm_lvm_vg_create_lv_linear, METH_VARARGS },
+       { NULL,      NULL}   /* sentinel */
+};
+
+static PyMethodDef liblvm_lv_methods[] = {
+       /* lv methods */
+       { "getName",            (PyCFunction)liblvm_lvm_lv_get_name, METH_NOARGS },
+       { "getUuid",            (PyCFunction)liblvm_lvm_lv_get_uuid, METH_NOARGS },
+       { "activate",           (PyCFunction)liblvm_lvm_lv_activate, METH_NOARGS },
+       { "deactivate",         (PyCFunction)liblvm_lvm_lv_deactivate, METH_NOARGS },
+       { "remove",             (PyCFunction)liblvm_lvm_vg_remove_lv, METH_NOARGS },
+       { "getProperty",        (PyCFunction)liblvm_lvm_lv_get_property, METH_VARARGS },
+       { "getSize",            (PyCFunction)liblvm_lvm_lv_get_size, METH_NOARGS },
+       { "isActive",           (PyCFunction)liblvm_lvm_lv_is_active, METH_NOARGS },
+       { "isSuspended",        (PyCFunction)liblvm_lvm_lv_is_suspended, METH_NOARGS },
+       { "addTag",             (PyCFunction)liblvm_lvm_lv_add_tag, METH_VARARGS },
+       { "removeTag",          (PyCFunction)liblvm_lvm_lv_remove_tag, METH_VARARGS },
+       { "getTags",            (PyCFunction)liblvm_lvm_lv_get_tags, METH_NOARGS },
+       { "rename",             (PyCFunction)liblvm_lvm_lv_rename, METH_VARARGS },
+       { "resize",             (PyCFunction)liblvm_lvm_lv_resize, METH_VARARGS },
+       { "listLVsegs",         (PyCFunction)liblvm_lvm_lv_list_lvsegs, METH_NOARGS },
+       { NULL,      NULL}   /* sentinel */
+};
+
+static PyMethodDef liblvm_pv_methods[] = {
+       /* pv methods */
+       { "getName",            (PyCFunction)liblvm_lvm_pv_get_name, METH_NOARGS },
+       { "getUuid",            (PyCFunction)liblvm_lvm_pv_get_uuid, METH_NOARGS },
+       { "getMdaCount",        (PyCFunction)liblvm_lvm_pv_get_mda_count, METH_NOARGS },
+       { "getProperty",        (PyCFunction)liblvm_lvm_pv_get_property, METH_VARARGS },
+       { "getSize",            (PyCFunction)liblvm_lvm_pv_get_size, METH_NOARGS },
+       { "getDevSize",         (PyCFunction)liblvm_lvm_pv_get_dev_size, METH_NOARGS },
+       { "getFree",            (PyCFunction)liblvm_lvm_pv_get_free, METH_NOARGS },
+       { "resize",             (PyCFunction)liblvm_lvm_pv_resize, METH_VARARGS },
+       { "listPVsegs",         (PyCFunction)liblvm_lvm_lv_list_pvsegs, METH_NOARGS },
+       { NULL,      NULL}   /* sentinel */
+};
+
+static PyMethodDef liblvm_lvseg_methods[] = {
+       { "getProperty",        (PyCFunction)liblvm_lvm_lvseg_get_property, METH_VARARGS },
+       { NULL,      NULL}   /* sentinel */
+};
+
+static PyMethodDef liblvm_pvseg_methods[] = {
+       { "getProperty",        (PyCFunction)liblvm_lvm_pvseg_get_property, METH_VARARGS },
+       { NULL,      NULL}   /* sentinel */
+};
+
+static PyTypeObject LiblvmType = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       .tp_name = "liblvm.Liblvm",
+       .tp_basicsize = sizeof(lvmobject),
+       .tp_new = PyType_GenericNew,
+       .tp_dealloc = (destructor)liblvm_dealloc,
+       .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+       .tp_doc = "Liblvm objects",
+       .tp_methods = Liblvm_methods,
+       .tp_init = (initproc)liblvm_init,
+};
+
+static PyTypeObject LibLVMvgType = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       .tp_name = "liblvm.Liblvm_vg",
+       .tp_basicsize = sizeof(vgobject),
+       .tp_new = PyType_GenericNew,
+       .tp_dealloc = (destructor)liblvm_vg_dealloc,
+       .tp_flags = Py_TPFLAGS_DEFAULT,
+       .tp_doc = "LVM Volume Group object",
+       .tp_methods = liblvm_vg_methods,
+};
+
+static PyTypeObject LibLVMlvType = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       .tp_name = "liblvm.Liblvm_lv",
+       .tp_basicsize = sizeof(lvobject),
+       .tp_new = PyType_GenericNew,
+       .tp_dealloc = (destructor)liblvm_lv_dealloc,
+       .tp_flags = Py_TPFLAGS_DEFAULT,
+       .tp_doc = "LVM Logical Volume object",
+       .tp_methods = liblvm_lv_methods,
+};
+
+static PyTypeObject LibLVMpvType = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       .tp_name = "liblvm.Liblvm_pv",
+       .tp_basicsize = sizeof(pvobject),
+       .tp_new = PyType_GenericNew,
+       .tp_dealloc = (destructor)liblvm_pv_dealloc,
+       .tp_flags = Py_TPFLAGS_DEFAULT,
+       .tp_doc = "LVM Physical Volume object",
+       .tp_methods = liblvm_pv_methods,
+};
+
+static PyTypeObject LibLVMlvsegType = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       .tp_name = "liblvm.Liblvm_lvseg",
+       .tp_basicsize = sizeof(lvsegobject),
+       .tp_new = PyType_GenericNew,
+       .tp_dealloc = (destructor)liblvm_lvseg_dealloc,
+       .tp_flags = Py_TPFLAGS_DEFAULT,
+       .tp_doc = "LVM Logical Volume Segment object",
+       .tp_methods = liblvm_lvseg_methods,
+};
+
+static PyTypeObject LibLVMpvsegType = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       .tp_name = "liblvm.Liblvm_pvseg",
+       .tp_basicsize = sizeof(pvsegobject),
+       .tp_new = PyType_GenericNew,
+       .tp_dealloc = (destructor)liblvm_pvseg_dealloc,
+       .tp_flags = Py_TPFLAGS_DEFAULT,
+       .tp_doc = "LVM Physical Volume Segment object",
+       .tp_methods = liblvm_pvseg_methods,
+};
+
+PyMODINIT_FUNC
+initlvm(void)
+{
+       PyObject *m;
+
+       if (PyType_Ready(&LiblvmType) < 0)
+               return;
+       if (PyType_Ready(&LibLVMvgType) < 0)
+               return;
+       if (PyType_Ready(&LibLVMlvType) < 0)
+               return;
+       if (PyType_Ready(&LibLVMpvType) < 0)
+               return;
+       if (PyType_Ready(&LibLVMlvsegType) < 0)
+               return;
+       if (PyType_Ready(&LibLVMpvsegType) < 0)
+               return;
+
+       m = Py_InitModule3("lvm", Liblvm_methods, "Liblvm module");
+       if (m == NULL)
+               return;
+
+       Py_INCREF(&LiblvmType);
+       PyModule_AddObject(m, "Liblvm", (PyObject *)&LiblvmType);
+
+       LibLVMError = PyErr_NewException("Liblvm.LibLVMError",
+                                        NULL, NULL);
+       if (LibLVMError) {
+               /* Each call to PyModule_AddObject decrefs it; compensate: */
+               Py_INCREF(LibLVMError);
+               Py_INCREF(LibLVMError);
+               PyModule_AddObject(m, "error", LibLVMError);
+               PyModule_AddObject(m, "LibLVMError", LibLVMError);
+       }
+
+}
diff --git a/python/setup.py.in b/python/setup.py.in
new file mode 100644 (file)
index 0000000..6a44482
--- /dev/null
@@ -0,0 +1,35 @@
+#
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from distutils.core import setup, Extension
+
+liblvm = Extension('lvm',
+                    sources = ['liblvm_python.c'],
+                    libraries= ['lvm2app'],
+                    library_dirs= ['@top_builddir@/liblvm'],
+                    include_dirs= ['@top_builddir@/include'])
+
+setup (name='lvm',
+       version=@LVM_VERSION@,
+       description='Python bindings for liblvm2',
+       license="LGPLv2+",
+       maintainer='LVM2 maintainers',
+       maintainer_email='linux-lvm@redhat.com',
+       url='http://sourceware.org/lvm2/',
+       ext_modules=[liblvm],
+)
index 5293cc358d291886d7b95108755085f089e47cef..91e2e94ab7c18dd46c12d9216c3171fc7f95d6eb 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2006-2010 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2006-2011 Red Hat, Inc. All rights reserved.
 #
 # This file is part of LVM2.
 #
@@ -15,19 +15,40 @@ srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 top_builddir = @top_builddir@
 
+ifeq ("@APPLIB@", "yes")
+       SOURCES = lvm2_activation_generator_systemd_red_hat.c
+       TARGETS = lvm2_activation_generator_systemd_red_hat
+endif
+
 include $(top_builddir)/make.tmpl
 
+ifeq ("@APPLIB@", "yes")
+       DEPLIBS += $(top_builddir)/liblvm/liblvm2app.so $(top_builddir)/libdm/libdevmapper.so
+       LDFLAGS += -L$(top_builddir)/liblvm
+       LVMLIBS = @LVM2APP_LIB@ -ldevmapper
+endif
+
+ifeq ("@DMEVENTD@", "yes")
+       LVMLIBS += -ldevmapper-event
+endif
+
 SCRIPTS = lvmdump.sh lvmconf.sh vgimportclone.sh
+
 ifeq ("@FSADM@", "yes")
        SCRIPTS += fsadm.sh
 endif
 
+ifeq ("@BLKDEACTIVATE@", "yes")
+       SCRIPTS += blkdeactivate.sh
+endif
+
 OCF_SCRIPTS =
 ifeq ("@OCF@", "yes")
         OCF_SCRIPTS += VolumeGroup.ocf
 endif
 
 vpath %.sh $(srcdir)
+vpath %.ocf $(srcdir)
 
 %_install: %.sh
        $(INSTALL_PROGRAM) -D $< $(sbindir)/$(basename $(<F))
@@ -45,12 +66,56 @@ install: install_lvm2 install_ocf
 # FIXME Customise for other distributions
 install_initscripts:
        $(INSTALL_DIR) $(initdir)
+ifeq ("@BUILD_DMEVENTD@", "yes")
        $(INSTALL_SCRIPT) lvm2_monitoring_init_red_hat $(initdir)/lvm2-monitor
+endif
+ifeq ("@BUILD_LVMETAD@", "yes")
+       $(INSTALL_SCRIPT) lvm2_lvmetad_init_red_hat $(initdir)/lvm2-lvmetad
+endif
 ifneq ("@CLVMD@", "none")
        $(INSTALL_SCRIPT) clvmd_init_red_hat $(initdir)/clvmd
 endif
 ifeq ("@BUILD_CMIRRORD@", "yes")
        $(INSTALL_SCRIPT) cmirrord_init_red_hat $(initdir)/cmirrord
 endif
+ifeq ("@BLKDEACTIVATE@", "yes")
+       $(INSTALL_SCRIPT) blk_availability_init_red_hat $(initdir)/blk-availability
+endif
+
+lvm2_activation_generator_systemd_red_hat: $(OBJECTS) $(DEPLIBS)
+       $(CC) -o $@ $(OBJECTS) $(LDFLAGS) $(LVMLIBS)
+
+install_systemd_generators:
+       $(INSTALL_DIR) $(systemd_generator_dir)
+ifeq ("@APPLIB@", "yes")
+       $(INSTALL_PROGRAM) lvm2_activation_generator_systemd_red_hat $(systemd_generator_dir)/lvm2-activation-generator
+else
+       @echo "WARNING: LVM2 activation systemd generator not installed." \
+             "It requires the LVM2 application library to be built as well."
+endif
+
+install_systemd_units:
+       $(INSTALL_DIR) $(systemd_unit_dir)
+ifeq ("@BUILD_DMEVENTD@", "yes")
+       $(INSTALL_DATA) dm_event_systemd_red_hat.socket $(systemd_unit_dir)/dm-event.socket
+       $(INSTALL_DATA) dm_event_systemd_red_hat.service $(systemd_unit_dir)/dm-event.service
+       $(INSTALL_DATA) lvm2_monitoring_systemd_red_hat.service $(systemd_unit_dir)/lvm2-monitor.service
+endif
+ifeq ("@BLKDEACTIVATE@", "yes")
+       $(INSTALL_DATA) blk_availability_systemd_red_hat.service $(systemd_unit_dir)/blk-availability.service
+endif
+ifeq ("@BUILD_LVMETAD@", "yes")
+       $(INSTALL_DATA) lvm2_lvmetad_systemd_red_hat.socket $(systemd_unit_dir)/lvm2-lvmetad.socket
+       $(INSTALL_DATA) lvm2_lvmetad_systemd_red_hat.service $(systemd_unit_dir)/lvm2-lvmetad.service
+endif
+
+install_tmpfiles_configuration:
+       $(INSTALL_DIR) $(tmpfiles_dir)
+       $(INSTALL_DATA) lvm2_tmpfiles_red_hat.conf $(tmpfiles_dir)/lvm2.conf
 
-DISTCLEAN_TARGETS += clvmd_init_red_hat cmirrord_init_red_hat lvm2_monitoring_init_red_hat
+DISTCLEAN_TARGETS += clvmd_init_red_hat cmirrord_init_red_hat \
+                    lvm2_monitoring_init_red_hat lvm2_lvmetad_init_red_hat \
+                    dm_event_systemd_red_hat.socket dm_event_systemd_red_hat.service \
+                    lvm2_monitoring_systemd_red_hat.service \
+                    lvm2_lvmetad_systemd_red_hat.socket lvm2_lvmetad_systemd_red_hat.service \
+                    lvm2_tmpfiles_red_hat.conf
diff --git a/scripts/blk_availability_init_red_hat.in b/scripts/blk_availability_init_red_hat.in
new file mode 100644 (file)
index 0000000..5638def
--- /dev/null
@@ -0,0 +1,58 @@
+#!/bin/bash
+#
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+#
+# This file is part of LVM2.
+# It is required for the proper handling of failures of LVM2 mirror
+# devices that were created using the -m option of lvcreate.
+#
+#
+# chkconfig: 12345 25 75
+# description: Controls availability of block devices
+#
+# For Red-Hat-based distributions such as Fedora, RHEL, CentOS.
+#             
+### BEGIN INIT INFO
+# Provides: blk-availability
+# Required-Start:
+# Required-Stop:
+# Default-Start: 1 2 3 4 5
+# Default-Stop: 0 6
+# Short-Description: Availability of block devices
+### END INIT INFO
+
+. /etc/init.d/functions
+
+sbindir=@sbindir@
+script=blkdeactivate
+options="-u -l wholevg"
+
+LOCK_FILE="/var/lock/subsys/blk-availability"
+
+
+rtrn=1
+
+case "$1" in
+  start)
+       touch $LOCK_FILE
+       ;;
+
+  stop)
+       action "Stopping block device availability:" $sbindir/$script $options
+       rm -f $LOCK_FILE
+       ;;
+
+  status)
+       ;;
+  *)
+       echo $"Usage: $0 {start|stop|status}"
+       ;;
+esac
diff --git a/scripts/blk_availability_systemd_red_hat.service.in b/scripts/blk_availability_systemd_red_hat.service.in
new file mode 100644 (file)
index 0000000..9c1cb78
--- /dev/null
@@ -0,0 +1,14 @@
+[Unit]
+Description=Availability of block devices
+After=lvm2-activation.service lvm2-lvmetad.service iscsi.service iscsid.service fcoe.service
+DefaultDependencies=no
+Conflicts=shutdown.target
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/true
+ExecStop=@sbindir@/blkdeactivate -u -l wholevg
+RemainAfterExit=yes
+
+[Install]
+WantedBy=sysinit.target
diff --git a/scripts/blkdeactivate.sh.in b/scripts/blkdeactivate.sh.in
new file mode 100644 (file)
index 0000000..740bac5
--- /dev/null
@@ -0,0 +1,313 @@
+#!/bin/bash
+#
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+#
+# Author: Peter Rajnoha <prajnoha at redhat.com>
+#
+# Script for deactivating block devices
+#
+# Requires:
+#   bash >= 4.0 (associative array support)
+#   lsblk >= 2.22 (lsblk -s support)
+#   umount
+#   dmsetup >= 1.02.68 (--retry option support)
+#   lvm >= 2.2.89 (activation/retry_deactivation config support)
+#
+
+#set -x
+shopt -s dotglob nullglob
+
+TOOL=blkdeactivate
+
+DEV_DIR='/dev'
+SYS_BLK_DIR='/sys/block'
+
+UMOUNT="/bin/umount"
+DMSETUP="@sbindir@/dmsetup"
+LVM="@sbindir@/lvm"
+
+LSBLK="/bin/lsblk -r --noheadings -o TYPE,KNAME,NAME,MOUNTPOINT"
+LSBLK_VARS="local devtype local kname local name local mnt"
+LSBLK_READ="read -r devtype kname name mnt"
+
+# Do not unmount mounted devices by default.
+DO_UMOUNT=0
+
+# Deactivate each LV separately by default (not the whole VG).
+LVM_DO_WHOLE_VG=0
+# Do not retry LV deactivation by default.
+LVM_CONFIG="activation{retry_deactivation=0}"
+
+#
+# List of device names and/or VGs to be skipped.
+# Device name is the KNAME from lsblk output.
+#
+# If deactivation of any device fails, it's automatically
+# added to the SKIP_DEVICE_LIST (also a particular VG
+# added to the SKIP_VG_LIST for a device that is an LV).
+#
+# These lists provide device tree pruning to skip
+# particular device/VG deactivation that failed already.
+# (lists are associative arrays!)
+#
+declare -A SKIP_DEVICE_LIST=()
+declare -A SKIP_VG_LIST=()
+
+#
+# List of mountpoints to be skipped. Any device that is mounted on the mountpoint
+# listed here will be added to SKIP_DEVICE_LIST (and SKIP_VG_LIST) automatically.
+# (list is an associative array!)
+#
+declare -A SKIP_UMOUNT_LIST=(["/"]=1 ["/boot"]=1 \
+                             ["/lib"]=1 ["/lib64"]=1 \
+                             ["/bin"]=1 ["/sbin"]=1 \
+                             ["/usr"]=1 \
+                             ["/usr/lib"]=1 ["/usr/lib64"]=1 \
+                             ["/usr/sbin"]=1 ["/usr/bin"]=1)
+# Bash can't properly handle '[' and ']' used as a subscript
+# within the '()'initialization - it needs to be done separately!
+SKIP_UMOUNT_LIST["[SWAP]"]=1
+
+usage() {
+       echo "${TOOL}: Utility to deactivate block devices"
+       echo
+       echo "  ${TOOL} [options] [device...]"
+       echo "    - Deactivate block device tree."
+       echo "      If devices are specified, deactivate only supplied devices and their holders."
+       echo
+       echo "  Options:"
+       echo "    -h | --help                  Show this help message"
+       echo "    -d | --dmoption  DM_OPTIONS  Comma separated DM specific options"
+       echo "    -l | --lvmoption LVM_OPTIONS Comma separated LVM specific options"
+       echo "    -u | --umount                Unmount the device if mounted"
+       echo
+       echo "  Device specific options:"
+       echo "    DM_OPTIONS:"
+       echo "      retry    retry removal several times in case of failure"
+       echo "      force    force device removal"
+       echo "    LVM_OPTIONS:"
+       echo "      retry    retry removal several times in case of failure"
+       echo "      wholevg  deactivate the whole VG when processing an LV"
+
+       exit
+}
+
+add_device_to_skip_list() {
+       SKIP_DEVICE_LIST+=(["$kname"]=1)
+       return 1
+}
+
+add_vg_to_skip_list() {
+       SKIP_VG_LIST+=(["$DM_VG_NAME"]=1)
+       return 1
+}
+
+is_top_level_device() {
+       # top level devices do not have any holders, that is
+       # the SYS_BLK_DIR/<device_name>/holders dir is empty
+       files="`echo $SYS_BLK_DIR/$kname/holders/*`"
+       test -z "$files"
+}
+
+device_umount () {
+       test -z "$mnt" && return 0;
+
+       if test -z "${SKIP_UMOUNT_LIST["$mnt"]}" -a "$DO_UMOUNT" -eq "1"; then
+               echo "  UMOUNT: unmounting $name ($kname) mounted on $mnt"
+               $UMOUNT "$mnt" || add_device_to_skip_list
+       else
+               echo "  [SKIP]: unmount of $name ($kname) mounted on $mnt"
+               add_device_to_skip_list
+       fi
+}
+
+deactivate_holders () {
+       local skip=1; $LSBLK_VARS
+
+       # Get holders for the device - either a mount or another device.
+       # First line on the lsblk output is the device itself - skip it for
+       # the deactivate call as this device is already being deactivated.
+       while $LSBLK_READ; do
+               test -e $SYS_BLK_DIR/$kname || continue
+               # check if the device not on the skip list already
+               test -z ${SKIP_DEVICE_LIST["$kname"]} || return 1
+
+               # try to unmount it if mounted
+               device_umount || return 1
+
+               # try to deactivate the holder
+               test $skip -eq 1 && skip=0 && continue
+               deactivate || return 1
+       done <<< "`$LSBLK $1`"
+}
+
+deactivate_dm () {
+       local name=$(printf $name)
+       test -b "$DEV_DIR/mapper/$name" || return 0
+       test -z ${SKIP_DEVICE_LIST["$kname"]} || return 1
+
+       deactivate_holders "$DEV_DIR/mapper/$name" || return 1
+
+       echo "  DM: deactivating $devtype device $name ($kname)"
+       $DMSETUP $DMSETUP_OPTS remove "$name" || add_device_to_skip_list
+}
+
+deactivate_lvm () {
+       local DM_VG_NAME; local DM_LV_NAME; local DM_LV_LAYER
+
+       eval $($DMSETUP splitname --nameprefixes --noheadings --rows "$name" LVM)
+       test -b "$DEV_DIR/$DM_VG_NAME/$DM_LV_NAME" || return 0
+       test -z ${SKIP_VG_LIST["$DM_VG_NAME"]} || return 1
+
+       # Deactivating only the LV specified
+       test $LVM_DO_WHOLE_VG -eq 0 && {
+               deactivate_holders "$DEV_DIR/$DM_VG_NAME/$DM_LV_NAME" || {
+                       add_device_to_skip_list
+                       return 1
+               }
+
+               echo "  LVM: deactivating Logical Volume $DM_VG_NAME/$DM_LV_NAME"
+               $LVM lvchange --config "log{prefix=\"\"} $LVM_CONFIG" -aln $DM_VG_NAME/$DM_LV_NAME || {
+                       add_device_to_skip_list
+                       return 1
+               }
+               return 0
+       }
+
+       # Deactivating the whole VG the LV is part of
+       lv_list=$($LVM vgs --config "$LVM_CONFIG" --noheadings --rows -o lv_name $DM_VG_NAME)
+       for lv in $lv_list; do
+               test -b "$DEV_DIR/$DM_VG_NAME/$lv" || continue
+               deactivate_holders "$DEV_DIR/$DM_VG_NAME/$lv" || {
+                       add_vg_to_skip_list
+                       return 1
+               }
+       done
+
+       echo "  LVM: deactivating Volume Group $DM_VG_NAME"
+       $LVM vgchange --config "log{prefix=\"    \"} $LVM_CONFIG" -aln $DM_VG_NAME || add_vg_to_skip_list
+}
+
+deactivate () {
+       ######################################################################
+       # DEACTIVATION HOOKS FOR NEW DEVICE TYPES GO HERE!                   #
+       #                                                                    #
+       # Identify a new device type either by inspecting the TYPE provided  #
+       # by lsblk directly ($devtype) or by any other mean that is suitable #
+       # e.g. the KNAME provided by lsblk ($kname). See $LSBLK_VARS for     #
+       # complete list of variables that may be used. Then call a           #
+       # device-specific deactivation function that handles the exact type. #
+       #                                                                    #
+        # This device-specific function will certainly need to call          #
+       # deactivate_holders first to recursively deactivate any existing    #
+       # holders it might have before deactivating the device it processes. #
+       ######################################################################
+       if test "$devtype" = "lvm"; then
+               deactivate_lvm
+       elif test "${kname:0:3}" = "dm-"; then
+               deactivate_dm
+       fi
+}
+
+deactivate_all() {
+       $LSBLK_VARS
+       skip=0
+
+       echo "Deactivating block devices:"
+
+       if test $# -eq 0; then
+               # Deactivate all devices
+               while $LSBLK_READ; do
+                       # 'disk' is at the bottom already and it's a real device
+                       test "$devtype" = "disk" && continue
+
+                       # if deactivation of any device fails, skip processing
+                       # any subsequent devices within its subtree as the
+                       # top-level device could not be deactivated anyway
+                       test $skip -eq 1 && {
+                               # reset 'skip' on top level device
+                               is_top_level_device && skip=0 || continue
+                       }
+
+                       # check if the device is not on the skip list already
+                       test -z ${SKIP_DEVICE_LIST["$kname"]} || continue
+
+                       # try to deactivate top-level device, set 'skip=1'
+                       # if it fails to do so - this will cause all the
+                       # device's subtree to be skipped when processing
+                       # devices further in this loop
+                       deactivate || skip=1
+               done <<< "`$LSBLK -s`"
+       else
+               # Deactivate only specified devices
+               while test $# -ne 0; do
+                       # Single dm device tree deactivation.
+                       if test -b "$1"; then
+                               $LSBLK_READ <<< "`$LSBLK --nodeps $1`"
+
+                               # check if the device is not on the skip list already
+                               test -z ${SKIP_DEVICE_LIST["$kname"]} || continue
+
+                               deactivate
+                       else
+                               echo "$1: device not found"
+                               return 1
+                       fi
+                       shift
+               done;
+       fi
+}
+
+get_dmopts() {
+       ORIG_IFS=$IFS; IFS=','
+
+       for opt in $1; do
+               case $opt in
+                       "") ;;
+                       "retry") DMSETUP_OPTS+="--retry " ;;
+                       "force") DMSETUP_OPTS+="--force " ;;
+                       *) echo "$opt: unknown DM option"
+               esac
+       done
+
+       IFS=$ORIG_IFS
+}
+
+get_lvmopts() {
+       ORIG_IFS=$IFS; IFS=','
+
+       for opt in $1; do
+               case "$opt" in
+                       "") ;;
+                       "retry") LVM_CONFIG="activation{retry_deactivation=1}" ;;
+                       "wholevg") LVM_DO_WHOLE_VG=1 ;;
+                       *) echo "$opt: unknown LVM option"
+               esac
+       done
+
+       IFS=$ORIG_IFS
+}
+
+while test $# -ne 0; do
+       case "$1" in
+               "") ;;
+               "-h"|"--help") usage ;;
+               "-d"|"--dmoption ") get_dmopts "$2" ; shift ;;
+               "-l"|"--lvmoption ") get_lvmopts "$2" ; shift ;;
+               "-u"|"--umount") DO_UMOUNT=1 ;;
+               *) break ;;
+       esac
+       shift
+done
+
+deactivate_all "$@"
index 3fc90c5cc4bb8d9a9fdc6a957a9ecd5a8f962860..41700942a3b6274ddaafa6752e21a25f901edf40 100644 (file)
@@ -87,7 +87,7 @@ start()
 
        ${lvm_vgscan} > /dev/null 2>&1
 
-       action "Activating VG(s):" ${lvm_vgchange} -ayl $LVM_VGS || return $?
+       action "Activating VG(s):" ${lvm_vgchange} -aay $LVM_VGS || return $?
 
        touch $LOCK_FILE
 
index ab3b7fb47acc0afe22deb188e9e6028e7225e835..a7150781634d1c71b0a5db90c5c5e04123e95b8a 100755 (executable)
@@ -21,6 +21,7 @@ LOCK_FILE="/var/lock/subsys/$DAEMON"
 
 start()
 {
+       rtrn=0
        if ! pidof $DAEMON > /dev/null 
        then 
                echo -n "Starting $DAEMON: "
diff --git a/scripts/dm_event_systemd_red_hat.service.in b/scripts/dm_event_systemd_red_hat.service.in
new file mode 100644 (file)
index 0000000..96c5225
--- /dev/null
@@ -0,0 +1,18 @@
+[Unit]
+Description=Device-mapper event daemon
+Documentation=man:dmeventd(8)
+Requires=dm-event.socket
+After=dm-event.socket
+Before=local-fs.target
+DefaultDependencies=no
+
+[Service]
+Type=forking
+ExecStart=@sbindir@/dmeventd
+ExecReload=@sbindir@/dmeventd -R
+Environment=SD_ACTIVATION=1
+PIDFile=@DMEVENTD_PIDFILE@
+OOMScoreAdjust=-1000
+
+[Install]
+WantedBy=sysinit.target
diff --git a/scripts/dm_event_systemd_red_hat.socket.in b/scripts/dm_event_systemd_red_hat.socket.in
new file mode 100644 (file)
index 0000000..b27c68d
--- /dev/null
@@ -0,0 +1,12 @@
+[Unit]
+Description=Device-mapper event daemon FIFOs
+Documentation=man:dmeventd(8)
+DefaultDependencies=no
+
+[Socket]
+ListenFIFO=@DEFAULT_DM_RUN_DIR@/dmeventd-server
+ListenFIFO=@DEFAULT_DM_RUN_DIR@/dmeventd-client
+SocketMode=0600
+
+[Install]
+WantedBy=sockets.target
old mode 100644 (file)
new mode 100755 (executable)
index c59dcb6..4624a1c
@@ -1,6 +1,6 @@
 #!/bin/bash
 #
-# Copyright (C) 2007-2010 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2007-2012 Red Hat, Inc. All rights reserved.
 #
 # This file is part of LVM2.
 #
@@ -31,6 +31,7 @@
 
 TOOL=fsadm
 
+_SAVEPATH=$PATH
 PATH=/sbin:/usr/sbin:/bin:/usr/sbin:$PATH
 
 # utilities
@@ -61,17 +62,19 @@ YES=${_FSADM_YES}
 DRY=0
 VERB=
 FORCE=
-EXTOFF=0
+EXTOFF=${_FSADM_EXTOFF:-0}
 DO_LVRESIZE=0
 FSTYPE=unknown
 VOLUME=unknown
 TEMPDIR="${TMPDIR:-/tmp}/${TOOL}_${RANDOM}$$/m"
+DM_DEV_DIR="${DM_DEV_DIR:-/dev}"
 BLOCKSIZE=
 BLOCKCOUNT=
 MOUNTPOINT=
 MOUNTED=
 REMOUNT=
 PROCMOUNTS="/proc/mounts"
+NULL="$DM_DEV_DIR/null"
 
 IFS_OLD=$IFS
 # without bash $'\n'
@@ -118,7 +121,7 @@ dry() {
                return 0
        fi
        verbose "Executing $@"
-       $@
+       "$@"
 }
 
 cleanup() {
@@ -127,7 +130,7 @@ cleanup() {
        test "$MOUNTPOINT" = "$TEMPDIR" && MOUNTPOINT="" temp_umount
        if [ -n "$REMOUNT" ]; then
                verbose "Remounting unmounted filesystem back"
-               dry $MOUNT "$VOLUME" "$MOUNTED"
+               dry "$MOUNT" "$VOLUME" "$MOUNTED"
        fi
        IFS=$IFS_OLD
        trap 2
@@ -138,11 +141,13 @@ cleanup() {
                # start LVRESIZE with the filesystem modification flag
                # and allow recursive call of fsadm
                _FSADM_YES=$YES
-               export _FSADM_YES
+               _FSADM_EXTOFF=$EXTOFF
+               export _FSADM_YES _FSADM_EXTOFF
                unset FSADM_RUNNING
-               dry exec $LVM lvresize $VERB $FORCE -r -L${NEWSIZE}b $VOLUME_ORIG
+               test -n "$LVM_BINARY" && PATH=$_SAVEPATH
+               dry exec "$LVM" lvresize $VERB $FORCE -r -L${NEWSIZE}b "$VOLUME_ORIG"
        fi
-        
+
        # error exit status for break
        exit ${1:-1}
 }
@@ -174,17 +179,18 @@ decode_size() {
 # dereference device name if it is symbolic link
 detect_fs() {
        VOLUME_ORIG=$1
-       VOLUME=${1#/dev/}
-       VOLUME=$($READLINK $READLINK_E "/dev/$VOLUME") || error "Cannot get readlink $1"
+       VOLUME=${1/#"${DM_DEV_DIR}/"/}
+       VOLUME=$("$READLINK" $READLINK_E "$DM_DEV_DIR/$VOLUME") || error "Cannot get readlink \"$1\""
        RVOLUME=$VOLUME
        case "$RVOLUME" in
+          # hardcoded /dev  since udev does not create these entries elsewhere
          /dev/dm-[0-9]*)
-               read </sys/block/${RVOLUME#/dev/}/dm/name SYSVOLUME 2>&1 && VOLUME="/dev/mapper/$SYSVOLUME"
+               read </sys/block/${RVOLUME#/dev/}/dm/name SYSVOLUME 2>&1 && VOLUME="$DM_DEV_DIR/mapper/$SYSVOLUME"
                ;;
        esac
-       # use /dev/null as cache file to be sure about the result
+       # use null device as cache file to be sure about the result
        # not using option '-o value' to be compatible with older version of blkid
-       FSTYPE=$($BLKID -c /dev/null -s TYPE "$VOLUME") || error "Cannot get FSTYPE of \"$VOLUME\""
+       FSTYPE=$("$BLKID" -c "$NULL" -s TYPE "$VOLUME") || error "Cannot get FSTYPE of \"$VOLUME\""
        FSTYPE=${FSTYPE##*TYPE=\"} # cut quotation marks
        FSTYPE=${FSTYPE%%\"*}
        verbose "\"$FSTYPE\" filesystem found on \"$VOLUME\""
@@ -193,12 +199,12 @@ detect_fs() {
 # check if the given device is already mounted and where
 # FIXME: resolve swap usage and device stacking
 detect_mounted()  {
-       test -e $PROCMOUNTS || error "Cannot detect mounted device $VOLUME"
+       test -e "$PROCMOUNTS" || error "Cannot detect mounted device \"$VOLUME\""
 
-       MOUNTED=$($GREP ^"$VOLUME" $PROCMOUNTS)
+       MOUNTED=$("$GREP" "^$VOLUME[ \t]" "$PROCMOUNTS")
 
        # for empty string try again with real volume name
-       test -z "$MOUNTED" && MOUNTED=$($GREP ^"$RVOLUME" $PROCMOUNTS)
+       test -z "$MOUNTED" && MOUNTED=$("$GREP" "^$RVOLUME[ \t]" "$PROCMOUNTS")
 
        # cut device name prefix and trim everything past mountpoint
        # echo translates \040 to spaces
@@ -207,8 +213,8 @@ detect_mounted()  {
 
        # for systems with different device names - check also mount output
        if test -z "$MOUNTED" ; then
-               MOUNTED=$(LANG=C $MOUNT | $GREP ^"$VOLUME")
-               test -z "$MOUNTED" && MOUNTED=$(LANG=C $MOUNT | $GREP ^"$RVOLUME")
+               MOUNTED=$(LANG=C "$MOUNT" | "$GREP" "^$VOLUME[ \t]")
+               test -z "$MOUNTED" && MOUNTED=$(LANG=C "$MOUNT" | "$GREP" "^$RVOLUME[ \t]")
                MOUNTED=${MOUNTED##* on }
                MOUNTED=${MOUNTED% type *} # allow type in the mount name
        fi
@@ -219,12 +225,12 @@ detect_mounted()  {
 # get the full size of device in bytes
 detect_device_size() {
        # check if blockdev supports getsize64
-       $BLOCKDEV 2>&1 | $GREP getsize64 >/dev/null
+       "$BLOCKDEV" 2>&1 | "$GREP" getsize64 >"$NULL"
        if test $? -eq 0; then
-               DEVSIZE=$($BLOCKDEV --getsize64 "$VOLUME") || error "Cannot read size of device \"$VOLUME\""
+               DEVSIZE=$("$BLOCKDEV" --getsize64 "$VOLUME") || error "Cannot read size of device \"$VOLUME\""
        else
-               DEVSIZE=$($BLOCKDEV --getsize "$VOLUME") || error "Cannot read size of device \"$VOLUME\""
-               SSSIZE=$($BLOCKDEV --getss "$VOLUME") || error "Cannot block size read device \"$VOLUME\""
+               DEVSIZE=$("$BLOCKDEV" --getsize "$VOLUME") || error "Cannot read size of device \"$VOLUME\""
+               SSSIZE=$("$BLOCKDEV" --getss "$VOLUME") || error "Cannot block size read device \"$VOLUME\""
                DEVSIZE=$(($DEVSIZE * $SSSIZE))
        fi
 }
@@ -237,14 +243,14 @@ round_up_block_size() {
 }
 
 temp_mount() {
-       dry $MKDIR -p -m 0000 "$TEMPDIR" || error "Failed to create $TEMPDIR"
-       dry $MOUNT "$VOLUME" "$TEMPDIR" || error "Failed to mount $TEMPDIR"
+       dry "$MKDIR" -p -m 0000 "$TEMPDIR" || error "Failed to create $TEMPDIR"
+       dry "$MOUNT" "$VOLUME" "$TEMPDIR" || error "Failed to mount $TEMPDIR"
 }
 
 temp_umount() {
-       dry $UMOUNT "$TEMPDIR" || error "Failed to umount $TEMPDIR"
-       dry $RMDIR "${TEMPDIR}" || error "Failed to remove $TEMPDIR"
-       dry $RMDIR "${TEMPDIR%%m}" || error "Failed to remove ${TEMPDIR%%m}"
+       dry "$UMOUNT" "$TEMPDIR" || error "Failed to umount \"$TEMPDIR\""
+       dry "$RMDIR" "${TEMPDIR}" || error "Failed to remove \"$TEMPDIR\""
+       dry "$RMDIR" "${TEMPDIR%%m}" || error "Failed to remove \"${TEMPDIR%%m}\""
 }
 
 yes_no() {
@@ -263,7 +269,7 @@ yes_no() {
 }
 
 try_umount() {
-       yes_no "Do you want to unmount \"$MOUNTED\"" && dry $UMOUNT "$MOUNTED" && return 0
+       yes_no "Do you want to unmount \"$MOUNTED\"" && dry "$UMOUNT" "$MOUNTED" && return 0
        error "Cannot proceed with mounted filesystem \"$MOUNTED\""
 }
 
@@ -277,13 +283,13 @@ validate_parsing() {
 ####################################
 resize_ext() {
        verbose "Parsing $TUNE_EXT -l \"$VOLUME\""
-       for i in $(LANG=C $TUNE_EXT -l "$VOLUME"); do
+       for i in $(LANG=C "$TUNE_EXT" -l "$VOLUME"); do
                case "$i" in
                  "Block size"*) BLOCKSIZE=${i##*  } ;;
                  "Block count"*) BLOCKCOUNT=${i##*  } ;;
                esac
        done
-       validate_parsing $TUNE_EXT
+       validate_parsing "$TUNE_EXT"
        decode_size $1 $BLOCKSIZE
        FSFORCE=$FORCE
 
@@ -293,14 +299,14 @@ resize_ext() {
                if test -n "$MOUNTED" ; then
                        # Forced fsck -f for umounted extX filesystem.
                        case "$-" in
-                         *i*) dry $FSCK $YES -f "$VOLUME" ;;
-                         *) dry $FSCK -f -p "$VOLUME" ;;
+                         *i*) dry "$FSCK" $YES -f "$VOLUME" ;;
+                         *) dry "$FSCK" -f -p "$VOLUME" ;;
                        esac
                fi
        fi
 
        verbose "Resizing filesystem on device \"$VOLUME\" to $NEWSIZE bytes ($BLOCKCOUNT -> $NEWBLOCKCOUNT blocks of $BLOCKSIZE bytes)"
-       dry $RESIZE_EXT $FSFORCE "$VOLUME" $NEWBLOCKCOUNT
+       dry "$RESIZE_EXT" $FSFORCE "$VOLUME" $NEWBLOCKCOUNT
 }
 
 #############################
@@ -312,19 +318,19 @@ resize_reiser() {
        detect_mounted && verbose "ReiserFS resizes only unmounted filesystem" && try_umount
        REMOUNT=$MOUNTED
        verbose "Parsing $TUNE_REISER \"$VOLUME\""
-       for i in $(LANG=C $TUNE_REISER "$VOLUME"); do
+       for i in $(LANG=C "$TUNE_REISER" "$VOLUME"); do
                case "$i" in
                  "Blocksize"*) BLOCKSIZE=${i##*: } ;;
                  "Count of blocks"*) BLOCKCOUNT=${i##*: } ;;
                esac
        done
-       validate_parsing $TUNE_REISER
+       validate_parsing "$TUNE_REISER"
        decode_size $1 $BLOCKSIZE
        verbose "Resizing \"$VOLUME\" $BLOCKCOUNT -> $NEWBLOCKCOUNT blocks ($NEWSIZE bytes, bs: $NEWBLOCKCOUNT)"
        if [ -n "$YES" ]; then
-               echo y | dry $RESIZE_REISER -s $NEWSIZE "$VOLUME"
+               echo y | dry "$RESIZE_REISER" -s $NEWSIZE "$VOLUME"
        else
-               dry $RESIZE_REISER -s $NEWSIZE "$VOLUME"
+               dry "$RESIZE_REISER" -s $NEWSIZE "$VOLUME"
        fi
 }
 
@@ -341,18 +347,18 @@ resize_xfs() {
                temp_mount || error "Cannot mount Xfs filesystem"
        fi
        verbose "Parsing $TUNE_XFS \"$MOUNTPOINT\""
-       for i in $(LANG=C $TUNE_XFS "$MOUNTPOINT"); do
+       for i in $(LANG=C "$TUNE_XFS" "$MOUNTPOINT"); do
                case "$i" in
                  "data"*) BLOCKSIZE=${i##*bsize=} ; BLOCKCOUNT=${i##*blocks=} ;;
                esac
        done
        BLOCKSIZE=${BLOCKSIZE%%[^0-9]*}
        BLOCKCOUNT=${BLOCKCOUNT%%[^0-9]*}
-       validate_parsing $TUNE_XFS
+       validate_parsing "$TUNE_XFS"
        decode_size $1 $BLOCKSIZE
        if [ $NEWBLOCKCOUNT -gt $BLOCKCOUNT ]; then
                verbose "Resizing Xfs mounted on \"$MOUNTPOINT\" to fill device \"$VOLUME\""
-               dry $RESIZE_XFS $MOUNTPOINT
+               dry "$RESIZE_XFS" $MOUNTPOINT
        elif [ $NEWBLOCKCOUNT -eq $BLOCKCOUNT ]; then
                verbose "Xfs filesystem already has the right size"
        else
@@ -387,7 +393,7 @@ resize() {
 #  only one supported
 ####################################
 diff_dates() {
-         echo $(( $($DATE -u -d"$1" +%s 2>/dev/null) - $($DATE -u -d"$2" +%s 2>/dev/null) ))
+         echo $(( $("$DATE" -u -d"$1" +%s 2>"$NULL") - $("$DATE" -u -d"$2" +%s 2>"$NULL") ))
 }
 
 ###################
@@ -404,7 +410,7 @@ check() {
          "ext2"|"ext3"|"ext4")
                IFS_CHECK=$IFS
                IFS=$NL
-               for i in $(LANG=C $TUNE_EXT -l "$VOLUME"); do
+               for i in $(LANG=C "$TUNE_EXT" -l "$VOLUME"); do
                        case "$i" in
                          "Last mount"*) LASTMOUNT=${i##*: } ;;
                          "Last checked"*) LASTCHECKED=${i##*: } ;;
@@ -424,11 +430,11 @@ check() {
        esac
 
        case "$FSTYPE" in
-         "xfs") dry $XFS_CHECK "$VOLUME" ;;
+         "xfs") dry "$XFS_CHECK" "$VOLUME" ;;
          *)    # check if executed from interactive shell environment
                case "$-" in
-                 *i*) dry $FSCK $YES $FORCE "$VOLUME" ;;
-                 *) dry $FSCK $FORCE -p "$VOLUME" ;;
+                 *i*) dry "$FSCK" $YES $FORCE "$VOLUME" ;;
+                 *) dry "$FSCK" $FORCE -p "$VOLUME" ;;
                esac
        esac
 }
@@ -446,15 +452,15 @@ test -n "$FSADM_RUNNING" && exit 0
 test -n "$TUNE_EXT" -a -n "$RESIZE_EXT" -a -n "$TUNE_REISER" -a -n "$RESIZE_REISER" \
   -a -n "$TUNE_XFS" -a -n "$RESIZE_XFS" -a -n "$MOUNT" -a -n "$UMOUNT" -a -n "$MKDIR" \
   -a -n "$RMDIR" -a -n "$BLOCKDEV" -a -n "$BLKID" -a -n "$GREP" -a -n "$READLINK" \
-  -a -n "$DATE" -a -n "$FSCK" -a -n "$XFS_CHECK" -a -n "LVM" \
+  -a -n "$DATE" -a -n "$FSCK" -a -n "$XFS_CHECK" -a -n "$LVM" \
   || error "Required command definitions in the script are missing!"
 
-$LVM version >/dev/null 2>&1 || error "Could not run lvm binary '$LVM'"
-$($READLINK -e / >/dev/null 2>&1) || READLINK_E="-f"
+"$LVM" version >"$NULL" 2>&1 || error "Could not run lvm binary \"$LVM\""
+$("$READLINK" -e / >"$NULL" 2>&1) || READLINK_E="-f"
 TEST64BIT=$(( 1000 * 1000000000000 ))
-test $TEST64BIT -eq 1000000000000000 || error "Shell does not handle 64bit arithmetic"
-$(echo Y | $GREP Y >/dev/null) || error "Grep does not work properly"
-test $($DATE -u -d"Jan 01 00:00:01 1970" +%s) -eq 1 || error "Date translation does not work"
+test "$TEST64BIT" -eq 1000000000000000 || error "Shell does not handle 64bit arithmetic"
+$(echo Y | "$GREP" Y >"$NULL") || error "Grep does not work properly"
+test $("$DATE" -u -d"Jan 01 00:00:01 1970" +%s) -eq 1 || error "Date translation does not work"
 
 
 if [ "$#" -eq 0 ] ; then
@@ -479,6 +485,9 @@ do
        shift
 done
 
+test "$YES" = "-y" || YES=
+test "$EXTOFF" -eq 1 || EXTOFF=0
+
 if [ -n "$CHECK" ]; then
        check "$CHECK"
 elif [ -n "$RESIZE" ]; then
diff --git a/scripts/gdbinit b/scripts/gdbinit
new file mode 100644 (file)
index 0000000..fa58948
--- /dev/null
@@ -0,0 +1,624 @@
+# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+# This file is part of LVM2.
+
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU Lesser General Public License v.2.1.
+
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# Author(s):
+#      Jonathan Brassow <jbrassow@redhat.com>
+#
+# Copy this file to ~/.gdbinit or <working_dir>/.gdbinit
+
+printf "\n\n"
+printf "Loading commands:\n"
+printf " - dm_list_size <list ptr>\n"
+printf " - pv_dev_name <PV ptr>\n"
+printf " - first_seg <LV ptr>\n"
+printf " - lv_status <LV ptr>\n"
+printf " - lv_status_r <LV ptr>\n"
+printf " - lv_is_mirrored <LV ptr>\n"
+printf " - seg_item <seg ptr> <index>\n"
+printf " - seg_status <seg ptr>\n"
+printf " - segs_using_this_lv <seg ptr>\n"
+printf " - seg_pvs <list ptr>\n"
+printf " - \n"
+printf "Use 'help <command>' for more info\n"
+printf "\n\n"
+printf "Popular breakpoints:\n"
+printf "break _alloc_image_components\n"
+printf "run --repair --use-policies vg/lv\n"
+printf "\n\n"
+
+set follow-fork-mode child
+
+# Conventions:
+# foo     : function named 'foo' available to user
+# __foo   : an internal function
+#
+# External functions should have a corresponding 'document'
+# section.  Internal functions should have leading comments
+
+
+
+define dm_list_size
+       set $_DLS_list_head = (struct dm_list *)$arg0
+       set $_DLS_list = $_DLS_list_head->n
+       set $_DLS_size = 0
+       
+       while (($_DLS_list != $_DLS_list_head) && ($_DLS_size < 100))
+               set $_DLS_list = $_DLS_list->n
+               set $_DLS_size++
+       end
+
+       printf "%d list items\n", $_DLS_size
+end
+
+document dm_list_size
+Returns the number of elements in the dm_list
+
+       Usage: dm_list_size <list ptr>
+end
+
+define pv_dev_name
+       set $_PDN_pv = (struct physical_volume *)$arg0
+       set $_PDN_dev = $_PDN_pv->dev
+       set $_PDN_strl = (struct str_list *)$_PDN_dev->aliases.n
+
+       printf "%s\n", $_PDN_strl->str
+end
+
+document pv_dev_name
+Print the name of the PV for the given PV pointer
+
+       Usage: pv_dev_name <PV ptr>
+end
+
+define seg_pvs
+       set $_SP_list_head = (struct dm_list *)$arg0
+       set $_SP_list = $_SP_list_head->n
+       
+       while (($_SP_list != $_SP_list_head) && ($_SP_size < 100))
+               set $_SP_spv = (struct seg_pvs *)$_SP_list
+
+               printf "* Can't print PV list\n"
+
+               set $_SP_list = $_SP_list->n
+       end
+
+       printf "%d list items\n", $_SP_size
+end
+
+document seg_pvs
+Print the elements of a seg_pvs list
+
+       Usage: seg_pvs <list ptr>
+end
+
+#
+# __first_seg <return> <LV>
+define __first_seg
+       set $arg0 = 0x0
+       set $_FS_lv  = (struct logical_volume *)$arg1
+
+       if ($_FS_lv->segments.n != &$_FS_lv->segments)
+               set $arg0 = (struct lv_segment *)$_FS_lv->segments.n
+       end
+end
+
+define first_seg
+       set $_seg = 0
+       set $_lv=(struct logical_volume *)$arg0
+
+       __first_seg $_seg $_lv
+
+       if ($_seg)
+               p $_seg
+       else
+               printf "No segments (list empty)\n"
+       end
+end
+
+document first_seg
+Returns the pointer to the first segment of an LV
+
+       Usage: first_seg <LV ptr>
+
+WARNING: If the list pointer in 'struct lv_segment' moves,
+        this function will be wrong.
+end
+
+#
+# __seg_type <return> <seg> <index>
+define __seg_type
+       set $arg0  = 0x0
+       set $_ST_seg  = (struct lv_segment *)$arg1
+       set $_ST_index= $arg2
+       set $_ST_area = $_ST_seg->areas[$_ST_index]
+       set $_ST_type = $_ST_area.type
+
+       set $arg0 = $_ST_type
+end
+
+#
+# __seg_item <return> <seg> <index>
+define __seg_item
+       set $arg0  = 0x0
+       set $_SI_seg  = (struct lv_segment *)$arg1
+       set $_SI_index= $arg2
+
+       if ($_SI_index < $_SI_seg->area_count)
+               set $_SI_area = $_SI_seg->areas[$_SI_index]
+               set $_SI_type = $_SI_area.type
+
+               if ($_SI_type == AREA_PV)
+                       set $arg0 = $_SI_area.u.pv.pvseg->pv
+               else
+                       if ($_SI_type == AREA_LV)
+                               set $arg0 = $_SI_area.u.lv.lv
+                       end
+               end
+       end
+end
+
+#
+# __seg_metaitem <return> <seg> <index>
+define __seg_metaitem
+       set $arg0  = 0x0
+       set $_SMI_seg  = (struct lv_segment *)$arg1
+       set $_SMI_index= $arg2
+
+       if (($_SMI_index < $_SMI_seg->area_count) && $_SMI_seg->meta_areas)
+               set $_SMI_area = $_SMI_seg->meta_areas[$_SMI_index]
+               set $_SMI_type = $_SMI_area.type
+
+               if ($_SMI_type == AREA_PV)
+                       set $arg0 = $_SMI_area.u.pv.pvseg->pv
+               else
+                       if ($_SMI_type == AREA_LV)
+                               set $arg0 = $_SMI_area.u.lv.lv
+                       end
+               end
+       end
+end
+
+define seg_item
+       set $_item = 0x0
+
+       __seg_item $_item $arg0 $arg1   
+       if ($_item)
+               p $_item
+       else
+               printf "AREA_UNASSIGNED or invalid\n"
+       end
+end
+
+define seg_metaitem
+       set $_metaitem = 0x0
+
+       __seg_metaitem $_metaitem $arg0 $arg1   
+       if ($_metaitem)
+               p $_metaitem
+       else
+               printf "AREA_UNASSIGNED or invalid\n"
+       end
+end
+
+document seg_item
+Returns the pointer to the LV or PV for the indexed area of a segment
+
+       Usage: seg_item <struct lv_segment *> <index>
+
+Example - Getting to the sub-lv of a mirror:
+       (gdb) p lv->name
+       $1 = 0x712548 "lv"
+
+       (gdb) first_seg lv
+       $2 = (struct lv_segment *) 0x7128b8
+
+       (gdb) seg_item $2 0
+       $3 = (struct logical_volume *) 0x712688
+
+       (gdb) p $3->name
+       $4 = 0x712770 "lv_mimage_0"
+end
+
+define __status
+       set $_s_status = $arg0->status
+
+#      Constants defined in metadata-exported.h
+
+#      if ($_s_status & RAID)
+       if ($_s_status & 0x0000000100000000LU)
+               set $_s_status = $_s_status & ~0x0000000100000000LU
+               printf " RAID"
+       end
+#      if ($_s_status & RAID_META)
+       if ($_s_status & 0x0000000200000000LU)
+               set $_s_status = $_s_status & ~0x0000000200000000LU
+               printf " RAID_META"
+       end
+#      if ($_s_status & RAID_IMAGE)
+       if ($_s_status & 0x0000000400000000LU)
+               set $_s_status = $_s_status & ~0x0000000400000000LU
+               printf " RAID_IMAGE"
+       end
+#      if ($_s_status & MIRRORED)
+       if ($_s_status & 0x00008000U)
+               set $_s_status = $_s_status & ~0x00008000U
+               printf " MIRRORED"
+       end
+#      if ($_s_status & MIRROR_LOG)
+       if ($_s_status & 0x00020000U)
+               set $_s_status = $_s_status & ~0x00020000U
+               printf " MIRROR_LOG"
+       end
+#      if ($_s_status & MIRROR_IMAGE)
+       if ($_s_status & 0x00040000U)
+               set $_s_status = $_s_status & ~0x00040000U
+               printf " MIRROR_IMAGE"
+       end
+#      if ($_s_status & VISIBLE_LV)
+       if ($_s_status & 0x00000040U)
+               printf " VISIBLE_LV"
+               set $_s_status = $_s_status & ~0x00000040U
+       else
+               printf " *HIDDEN_LV*"
+       end
+#      if ($_s_status & FIXED_MINOR)
+       if ($_s_status & 0x00000080U)
+               set $_s_status = $_s_status & ~0x00000080U
+               printf " FIXED_MINOR"
+       end
+#      if ($_s_status & LVM_READ)
+       if ($_s_status & 0x00000100U)
+               set $_s_status = $_s_status & ~0x00000100U
+               printf " LVM_READ"
+       end
+#      if ($_s_status & LVM_WRITE)
+       if ($_s_status & 0x00000200U)
+               set $_s_status = $_s_status & ~0x00000200U
+               printf " LVM_WRITE"
+       end
+#      if ($_s_status & SNAPSHOT)
+       if ($_s_status & 0x00001000U)
+               set $_s_status = $_s_status & ~0x00001000U
+               printf " SNAPSHOT"
+       end
+#      if ($_s_status & PVMOVE)
+       if ($_s_status & 0x00002000U)
+               set $_s_status = $_s_status & ~0x00002000U
+               printf " PVMOVE"
+       end
+#      if ($_s_status & LOCKED)
+       if ($_s_status & 0x00004000U)
+               set $_s_status = $_s_status & ~0x00004000U
+               printf " LOCKED"
+       end
+#      if ($_s_status & LV_NOTSYNCED)
+       if ($_s_status & 0x00080000U)
+               set $_s_status = $_s_status & ~0x00080000U
+               printf " LV_NOTSYNCED"
+       end
+#      if ($_s_status & CONVERTING)
+       if ($_s_status & 0x00400000U)
+               set $_s_status = $_s_status & ~0x00400000U
+               printf " CONVERTING"
+       end
+#      if ($_s_status & LV_REBUILD)
+       if ($_s_status & 0x100000U)
+               set $_s_status = $_s_status & ~0x100000U
+               printf " LV_REBUILD"
+       end
+#      if ($_s_status & PARTIAL_LV)
+       if ($_s_status & 0x1000000U)
+               set $_s_status = $_s_status & ~0x1000000U
+               printf " PARTIAL_LV"
+       end
+#      if ($_s_status & MERGING)
+       if ($_s_status & 0x10000000U)
+               set $_s_status = $_s_status & ~0x10000000U
+               printf " MERGING"
+       end
+
+       if ($_s_status)
+               printf " 0x%x", $_s_status
+       end
+end
+
+#
+# __print_indent <num indents> [No marks]
+define __print_indent
+       set $_PI_indent = $arg0
+       set $_PI_lead_mark = 0
+
+       while ($_PI_indent)
+               if ($_PI_indent == 1)
+                       if ($argc > 1)
+                               if ($_PI_lead_mark)
+                                       printf "        "
+                               else
+                                       printf "|       "
+                               end
+                       else
+                               printf "|-----> "
+                       end
+               else
+                       printf "|       "
+                       set $_PI_lead_mark = 1
+               end
+               set $_PI_indent--
+       end
+end
+
+define lv_status
+       # Use __lv because we don't want to overwrite higher functions
+       set $__lv = (struct logical_volume *)$arg0
+
+       if ($argc == 2)
+               __print_indent $arg1
+       end
+       printf "%s->status:", $__lv->name
+       __status $__lv
+       printf "\n"
+end
+
+document lv_status
+Display the flags that are set on an LV.
+
+       Usage: lv_status <LV ptr>
+end
+
+define seg_status
+       set $_seg=(struct lv_segment *)$arg0
+
+       if ($argc == 2)
+               __print_indent $arg1 1
+       end
+       printf "[ (%s) seg->status:", $_seg->lv->name
+       __status $_seg
+       printf " ]\n"
+end
+
+document seg_status
+Display the flags that are set on an lv_segment.
+
+        Usage: seg_status <(struct lv_segment *)>
+end
+
+#
+# get_only_segment_using_this_lv <return> <LV>
+define __get_only_segment_using_this_lv
+       set $arg0 = 0x0
+       set $_lv=(struct logical_volume *)$arg1
+       set $_seg_list_head = &$_lv->segs_using_this_lv
+       set $_s = $_lv->segs_using_this_lv.n
+       set $_i = 0
+
+       while (($_s != $_seg_list_head) && ($_i < 100))
+               set $_seg_list = (struct seg_list *)$_s
+               set $_seg = (struct lv_segment *)$_seg_list->seg
+
+               set $_i++
+               set $_s = $_s->n
+       end
+
+       if ($_i > 1)
+               printf "More than %s using %s\n", ($_i > 99) ? "100 segments" : "one segment", $_lv->name
+       end
+       if ($_i == 1)
+               set $arg0 = $_seg
+       end
+end
+
+define segs_using_this_lv
+       set $_lv=(struct logical_volume *)$arg0
+       set $_seg_list_head = &$_lv->segs_using_this_lv
+       set $_s = $_lv->segs_using_this_lv.n
+       set $_i = 0
+
+       if ($_s != $_seg_list_head)
+               printf "Segments using %s\n", $_lv->name
+       else
+               printf "No segments using %s\n", $_lv->name
+       end
+       while ($_s != $_seg_list_head)
+               set $_seg_list = (struct seg_list *)$_s
+               set $_seg = (struct lv_segment *)$_seg_list->seg
+               printf "  %d) seg: %p", $_i, $_seg
+               if ($_seg->lv < 0x200)
+                       printf "  [BAD LV POINTER FROM THIS SEG]\n"
+               else
+                       printf "  [seg found in %s]\n", $_seg->lv->name
+               end
+               set $_i++
+               set $_s = $_s->n
+       end
+end
+
+document segs_using_this_lv
+Display the segments (and their associated LV) using an LV
+
+       Usage: segs_using_this_lv <LV ptr>
+
+Example:
+       (gdb) lv_is_mirrored lv
+       lv is mirrored ('core' log)
+
+       (gdb) segs_using_this_lv lv
+       No segments using lv
+
+       (gdb) first_seg lv
+       $1 = (struct lv_segment *) 0x92d360
+
+       (gdb) seg_item $1 0
+       $2 = (struct logical_volume *) 0x928f58
+
+       (gdb) segs_using_this_lv $2
+       Segments using lv_mimage_0
+         0) seg: 0x92d360  [seg found in lv]
+end
+
+#
+# __next_area_index <return> <seg> <seg_item>
+define __next_area_index
+       set $arg0 = 0x0
+       set $_seg = (struct lv_segment *)$arg1
+       set $_item = 0x0
+       set $_i = 0
+
+       __seg_item $_item $_seg $_i
+       while ($_item && ($_item != $arg2))
+               set $_i++
+               __seg_item $_item $_seg $_i
+       end
+
+       # $_i points to current, now get next (if there)
+       set $_i++
+       __seg_item $_item $_seg $_i
+
+       if ($_item)
+               set $arg0 = $_i
+       end
+end
+
+#
+# __lv_status_r <LV>
+# Decend tree, printing LV and seg status as we go.  This
+# performs a depth first approach (but can't come up) 
+#
+# or
+#
+# __lv_status_r <sub_lv> <seg using sub_lv>
+# Try continuing decent of tree by first shifting to the
+# next 'area' in the seg ($arg1).  If no more areas, then
+# try going to the next segment.
+define __lv_status_r
+       if ($argc == 1)
+               set $_lv=(struct logical_volume *)$arg0
+               set $_seg_list_head = &$_lv->segments
+               set $_s = $_lv->segments.n
+               set $_area_index = 0
+
+#              printf "\n"
+               lv_status $_lv $indent
+       else
+               set $_seg = (struct lv_segment *)$arg1
+
+               __next_area_index $_area_index $_seg $arg0
+
+               # Don't fuck this up.  We need the next two lines here.
+               set $_lv=(struct logical_volume *)$_seg->lv
+               set $_seg_list_head = &$_lv->segments
+               set $_s = (struct dm_list *)$_seg
+
+               if (!$_area_index)
+                       set $_s = $_s->n
+               end
+       end
+
+       if ($_s == $_seg_list_head)
+               if ($argc == 1)
+                       __print_indent $indent 1
+                       printf "[ No segments for %s ]\n", $_lv->name
+               end
+               __get_only_segment_using_this_lv $_seg $_lv
+
+               if ($_seg && $indent)
+                       set $indent--
+                       __lv_status_r $_lv $_seg
+               end
+       else
+               set $_seg = (struct lv_segment *)$_s
+               set $_type = 0x0
+
+               if (!$_area_index)
+                       seg_status $_seg $indent
+               end
+               __seg_type $_type $_seg $_area_index
+               if ($_type == AREA_LV)
+                       set $indent++
+
+                       __seg_metaitem $_lv $_seg $_area_index
+                       if ($_lv)
+                               set $rindent = $indent
+                               set $rseg = $_seg
+                               set $rarea_index = $_area_index
+                               set $rlv = $_lv
+
+                               __lv_status_r $_lv
+
+                               set $indent = $rindent
+                               set $_seg = $rseg
+                               set $_area_index = $rarea_index
+                               set $_lv = $rlv
+                       end
+
+                       __seg_item $_lv $_seg $_area_index
+                       __lv_status_r $_lv
+               else
+                       if ($_seg->log_lv)
+                               set $indent++
+                               set $_log_seg = 0x0
+
+                               __first_seg $_log_seg $_seg->log_lv
+                               lv_status $_seg->log_lv $indent
+                               seg_status $_log_seg $indent
+
+                               set $indent--
+                       end
+                       __get_only_segment_using_this_lv $_seg $_lv
+                       if ($_seg)
+                               set $indent--
+                               __lv_status_r $_lv $_seg
+                       end
+               end
+       end
+end
+
+define lv_status_r
+       set $indent = 0
+       __lv_status_r $arg0
+end
+
+document lv_status_r
+Display the status flags of an LV and its sub_lvs.
+
+       Usage: lv_status_r <LV ptr>
+
+This function is useful for checking that all the LVs that
+compose a logical volume have the correct flags set (and also
+their associated lv_segments)
+end
+
+define lv_is_mirrored
+       set $_lv=(struct logical_volume *)$arg0
+       set $_fs=(struct lv_segment *)$_lv->segments.n
+       set $_log_lv=(struct logical_volume *)$_fs->log_lv
+
+#      if ($_lv->status & MIRRORED)
+       if ($_lv->status & 0x00008000U)
+               printf "%s is mirrored (", $_lv->name
+               if ($_log_lv)
+                       if ($_log_lv->status & 0x00008000U)
+                               printf "'mirrored' log)\n"
+                       else
+                               printf "'disk' log)\n"
+                       end
+               else
+                       printf "'core' log)\n"
+               end
+       else
+               printf "%s is not mirrored\n", $_lv->name
+       end
+end
+
+document lv_is_mirrored
+Report whether the given LV is mirrored (and its log type).
+
+       Usage: lv_is_mirrored <LV ptr>
+end
diff --git a/scripts/last_cvs_update.sh b/scripts/last_cvs_update.sh
deleted file mode 100755 (executable)
index 97b77c1..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-#!/bin/bash
-#$Header: /sourceware/projects/lvm2-home/cvsfiles/LVM2/scripts/last_cvs_update.sh,v 1.2 2010/05/14 11:33:21 zkabelac Exp $
-################################################################################
-##
-##    Copyright 2001 Sistina Software, Inc.
-##
-##    This is free software released under the GNU General Public License.
-##    There is no warranty for this software.  See the file COPYING for
-##    details.
-##
-##    See the file CONTRIBUTORS for a list of contributors.
-##
-##    This file is maintained by:
-##      AJ Lewis <lewis@sistina.com>
-## 
-##    File name: last_cvs_update.sh
-##
-##    Description: displays the last file updated by CVS commands and the date
-##                 it was updated.  May be given a relative or absolute path.
-##                 Based on this information, you should be able to do a 
-##                 cvs co -D $date GFS and get the same version of the source
-##                 tree as this tool was run on.
-##                 
-##                 Will also give you the CVS tag the source tree is based off
-##                 off when appropriate
-## 
-##                 Output format:
-##                 [Tag:  $TAG]
-##                 The last file updated by CVS was:
-##                 $path/$file
-##                 on
-##                 $date
-##
-################################################################################
-
-if [[ -z $1 ]];
- then path=.;
-else
- if [[ $1 == "-h" ]];
-   then echo "usage: $0 [ -h | path ]"
-        exit 0;
- else
-   if [[ -d $1 ]]
-     then path=$1;
-   else
-     echo "usage: $0 [ -h | path ]"
-     exit 0;
-   fi
- fi
-fi
-
-# grab the tag from the path passed in
-if [[ -f $path/CVS/Tag ]];
-  then echo "Tag: " `cat $path/CVS/Tag | sed -e 's/^[NT]//'`
-fi
-
-awk '
-BEGIN {                            
-  FS = "/"                         
-}
-{
-    # find the path for the Entries file
-    path = FILENAME
-    sub(/^\.\//, "", path)
-    
-    # remove the CVS part of it
-    sub(/CVS\/Entries/, "", path)
-    
-    # add the path the the filename that was modified, and put the date it was
-    # modified in as well
-    print path $2 " " $4
-
-}' `find $path -name "Entries" -printf "%h/%f "` | awk '
-# converts string name of month the a numeral
-function cvt_month(month) {
-  if(month == "Jan")
-    return 0
-  if(month == "Feb")
-    return 1
-  if(month == "Mar")
-    return 2
-  if(month == "Apr")
-    return 3
-  if(month == "May")
-    return 4
-  if(month == "Jun")
-    return 5
-  if(month == "Jul")
-    return 6
-  if(month == "Aug")
-    return 7
-  if(month == "Sep")
-    return 8
-  if(month == "Oct")
-    return 9
-  if(month == "Nov")
-    return 10
-  if(month == "Dec")
-    return 11
-  return -1
-}
-BEGIN {                            
-  FS = " "                         
-  latest=""
-  maxyear = 0
-  maxdate = 0
-  maxmonth = "Jan"
-  maxtime = "00:00:00"
-}
-{
-   # check year first
-   if (maxyear < $6) {
-      date = $2 " " $3 " " $4 " " $5 " " $6
-      file = $1
-      maxyear = $6
-      maxmonth = $3
-      maxdate = $4
-      maxtime = $5
-   }
-   else {
-      if (maxyear == $6) {
-        # then month if year is the same
-        if (cvt_month(maxmonth) < cvt_month($3)) {
-          date = $2 " " $3 " " $4 " " $5 " " $6
-          file = $1
-         maxmonth = $3
-         maxdate = $4
-         maxtime = $5
-        }
-        else {
-          if (cvt_month(maxmonth) == cvt_month($3)) {
-           #then date if month is the same
-            if (maxdate < $4) {
-              date = $2 " " $3 " " $4 " " $5 " " $6
-              file = $1
-             maxdate = $4
-             maxtime = $5
-           }
-           else {
-             if (maxdate == $4) {
-               # then time if date is the same
-               if (maxtime < $5) {
-                 date = $2 " " $3 " " $4 " " $5 " " $6
-                  file = $1
-                 maxtime = $5
-               }
-              }
-           }
-         }
-        }
-      }
-   }
-}
-
-END {
-   # strip leading "./" from filename
-   sub(/^\.\//, "", file)
-   print "The last file updated by CVS was:"
-   print file 
-   print "on"
-   print date " GMT"
-}'
-
diff --git a/scripts/lvm2_activation_generator_systemd_red_hat.c b/scripts/lvm2_activation_generator_systemd_red_hat.c
new file mode 100644 (file)
index 0000000..dfd6fc4
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of the device-mapper userspace tools.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * 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 <unistd.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "lvm2app.h"
+
+#define KMSG_DEV_PATH        "/dev/kmsg"
+#define LVM_CONF_USE_LVMETAD "global/use_lvmetad"
+
+#define DEFAULT_UNIT_DIR     "/tmp"
+#define UNIT_NAME_EARLY      "lvm2-activation-early.service"
+#define UNIT_NAME            "lvm2-activation.service"
+#define UNIT_TARGET          "local-fs.target"
+
+static char unit_path[PATH_MAX];
+static char target_path[PATH_MAX];
+static char message[PATH_MAX];
+static int kmsg_fd = -1;
+
+__attribute__ ((format(printf, 1, 2)))
+static void kmsg(const char *format, ...)
+{
+       va_list ap;
+       int n;
+
+       va_start(ap, format);
+       n = vsnprintf(message, sizeof(message), format, ap);
+       va_end(ap);
+
+       if (kmsg_fd < 0 || (n < 0 || ((unsigned) n + 1 > sizeof(message))))
+               return;
+
+       (void) write(kmsg_fd, message, n + 1);
+}
+
+static int lvm_uses_lvmetad(void)
+{
+       lvm_t lvm;
+       int r;
+
+       if (!(lvm = lvm_init(NULL))) {
+               kmsg("LVM: Failed to initialize library context for activation generator.\n");
+               return 0;
+       }
+       r = lvm_config_find_bool(lvm, LVM_CONF_USE_LVMETAD, 0);
+       lvm_quit(lvm);
+
+       return r;
+}
+
+static int register_unit_with_target(const char *dir, const char *unit, const char *target)
+{
+       int r = 1;
+
+       if (dm_snprintf(target_path, PATH_MAX, "%s/%s.wants", dir, target) < 0) {
+               r = 0; goto out;
+       }
+       (void) dm_prepare_selinux_context(target_path, S_IFDIR);
+       if (mkdir(target_path, 0755) < 0 && errno != EEXIST) {
+               kmsg("LVM: Failed to create target directory %s: %m.\n", target_path);
+               r = 0; goto out;
+       }
+
+       if (dm_snprintf(target_path, PATH_MAX, "%s/%s.wants/%s", dir, target, unit) < 0) {
+               r = 0; goto out;
+       }
+       (void) dm_prepare_selinux_context(target_path, S_IFLNK);
+       if (symlink(unit_path, target_path) < 0) {
+               kmsg("LVM: Failed to create symlink for unit %s: %m.\n", unit);
+               r = 0;
+       }
+out:
+       dm_prepare_selinux_context(NULL, 0);
+       return r;
+}
+
+static int generate_unit(const char *dir, int early)
+{
+       FILE *f;
+       const char *unit = early ? UNIT_NAME_EARLY : UNIT_NAME;
+
+       if (dm_snprintf(unit_path, PATH_MAX, "%s/%s", dir, unit) < 0)
+               return 0;
+
+       if (!(f = fopen(unit_path, "wxe"))) {
+               kmsg("LVM: Failed to create unit file %s: %m.\n", unit);
+               return 0;
+       }
+
+       fputs("# Automatically generated by lvm2-activation-generator.\n"
+             "#\n"
+             "# This unit is responsible for direct activation of LVM2 logical volumes\n"
+             "# if lvmetad daemon is not used (global/use_lvmetad=0 lvm.conf setting),\n"
+             "# hence volume autoactivation is not applicable.\n"
+             "# Direct LVM2 activation requires udev to be settled!\n\n"
+             "[Unit]\n"
+             "Description=Activation of LVM2 logical volumes\n"
+             "Documentation=man:lvm(8) man:vgchange(8)\n"
+             "SourcePath=/etc/lvm/lvm.conf\n"
+             "DefaultDependencies=no\n", f);
+
+       if (early) {
+               fputs("After=systemd-udev-settle.service\n", f);
+               fputs("Before=cryptsetup.target\n", f);
+       } else
+               fputs("After=lvm2-activation-early.service cryptsetup.target\n", f);
+
+       fputs("Before=local-fs.target shutdown.target\n"
+             "Wants=systemd-udev-settle.service\n\n"
+             "[Service]\n"
+             "ExecStart=/usr/sbin/lvm vgchange -aay --sysinit\n"
+             "Type=oneshot\n", f);
+
+       if (fclose(f) < 0) {
+               kmsg("LVM: Failed to write unit file %s: %m.\n", unit);
+               return 0;
+       }
+
+       if (!register_unit_with_target(dir, unit, UNIT_TARGET)) {
+               kmsg("LVM: Failed to register unit %s with target %s.\n", unit, UNIT_TARGET);
+               return 0;
+       }
+
+       return 1;
+}
+
+int main(int argc, char *argv[])
+{
+       const char *dir;
+       int r = EXIT_SUCCESS;
+
+       kmsg_fd = open(KMSG_DEV_PATH, O_WRONLY|O_NOCTTY);
+
+       if (argc > 1 && argc != 4) {
+               kmsg("LVM: Activation generator takes three or no arguments.\n");
+               r = EXIT_FAILURE; goto out;
+       }
+
+       /* If lvmetad used, rely on autoactivation instead of direct activation. */
+       if (lvm_uses_lvmetad()) {
+               kmsg("LVM: Logical Volume autoactivation enabled.\n");
+               goto out;
+       }
+
+       dir = argc > 1 ? argv[1] : DEFAULT_UNIT_DIR;
+
+       if (!generate_unit(dir, 1) || !generate_unit(dir, 0))
+               r = EXIT_FAILURE;
+out:
+       kmsg("LVM: Activation generator %s.\n", r ? "failed" : "successfully completed");
+       if (kmsg_fd != -1)
+               (void) close(kmsg_fd);
+       return r;
+}
diff --git a/scripts/lvm2_lvmetad_init_red_hat.in b/scripts/lvm2_lvmetad_init_red_hat.in
new file mode 100644 (file)
index 0000000..08e920e
--- /dev/null
@@ -0,0 +1,112 @@
+#!/bin/bash
+#
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+#
+# This file is part of LVM2.
+# It is required for the proper handling of failures of LVM2 mirror
+# devices that were created using the -m option of lvcreate.
+#
+#
+# chkconfig: 12345 02 99
+# description: Starts and stops LVM metadata daemon
+#
+# For Red-Hat-based distributions such as Fedora, RHEL, CentOS.
+#
+### BEGIN INIT INFO
+# Provides: lvm2-lvmetad
+# Required-Start: $local_fs
+# Required-Stop: $local_fs
+# Default-Start: 1 2 3 4 5
+# Default-Stop: 0 6
+# Short-Description: A daemon that maintains LVM metadata state for improved
+#                    performance by avoiding further scans while running
+#                    subsequent LVM commands or while using lvm2app library.
+### END INIT INFO
+
+. /etc/init.d/functions
+
+DAEMON=lvmetad
+
+exec_prefix=@exec_prefix@
+sbindir=@sbindir@
+
+LOCK_FILE="/var/lock/subsys/$DAEMON"
+PID_FILE="@LVMETAD_PIDFILE@"
+
+rh_status() {
+       status -p $PID_FILE $DAEMON
+}
+
+rh_status_q() {
+       rh_status >/dev/null 2>&1
+}
+
+start()
+{
+       ret=0
+       action "Starting LVM metadata daemon:" $DAEMON || ret=$?
+       return $ret
+}
+
+
+stop()
+{
+       ret=0
+       action "Signaling LVM metadata daemon to exit:" killproc -p $PID_FILE $DAEMON -TERM || ret=$?
+       return $ret
+}
+
+rtrn=1
+
+# See how we were called.
+case "$1" in
+  start)
+       rh_status_q && exit 0
+       start
+       rtrn=$?
+       [ $rtrn = 0 ] && touch $LOCK_FILE
+       ;;
+
+  stop|force-stop)
+       rh_status_q || exit 0
+       stop
+       rtrn=$?
+       [ $rtrn = 0 ] && rm -f $LOCK_FILE
+       ;;
+
+  restart)
+       if stop
+       then
+               start
+       fi
+       rtrn=$?
+       ;;
+
+  condrestart|try-restart)
+       rh_status_q || exit 0
+       if stop
+       then
+               start
+       fi
+       rtrn=$?
+       ;;
+
+  status)
+       rh_status
+       rtrn=$?
+       ;;
+
+  *)
+       echo $"Usage: $0 {start|stop|force-stop|restart|condrestart|try-restart|status}"
+       ;;
+esac
+
+exit $rtrn
diff --git a/scripts/lvm2_lvmetad_systemd_red_hat.service.in b/scripts/lvm2_lvmetad_systemd_red_hat.service.in
new file mode 100644 (file)
index 0000000..0150726
--- /dev/null
@@ -0,0 +1,19 @@
+[Unit]
+Description=LVM2 metadata daemon
+Documentation=man:lvmetad(8)
+Requires=lvm2-lvmetad.socket
+After=lvm2-lvmetad.socket
+DefaultDependencies=no
+Conflicts=shutdown.target
+
+[Service]
+Type=forking
+NonBlocking=true
+ExecStart=@sbindir@/lvmetad
+ExecReload=@sbindir@/lvmetad -R
+Environment=SD_ACTIVATION=1
+Restart=on-abort
+PIDFile=@LVMETAD_PIDFILE@
+
+[Install]
+WantedBy=sysinit.target
diff --git a/scripts/lvm2_lvmetad_systemd_red_hat.socket.in b/scripts/lvm2_lvmetad_systemd_red_hat.socket.in
new file mode 100644 (file)
index 0000000..9a46f50
--- /dev/null
@@ -0,0 +1,11 @@
+[Unit]
+Description=LVM2 metadata daemon socket
+Documentation=man:lvmetad(8)
+DefaultDependencies=no
+
+[Socket]
+ListenStream=@DEFAULT_RUN_DIR@/lvmetad.socket
+SocketMode=0600
+
+[Install]
+WantedBy=sockets.target
index 4812c750fefd8aa0e63c76eedc2b5b5dcd50a71f..cae652c90d6648e3b8a8676fa17bf7e83890dc6b 100644 (file)
@@ -42,15 +42,16 @@ VGS=${sbindir}/vgs
 LOCK_FILE="/var/lock/subsys/$DAEMON"
 
 WARN=1
+export LVM_SUPPRESS_LOCKING_FAILURE_MESSAGES=1
 
 start()
 {
        ret=0
        # TODO do we want to separate out already active groups only?
-       VGSLIST=`$VGS --noheadings -o name 2> /dev/null`
+       VGSLIST=`$VGS --noheadings -o name --config 'log{command_names=0 prefix="  "}' 2> /dev/null`
        for vg in $VGSLIST
        do
-           action "Starting monitoring for VG $vg:" $VGCHANGE --monitor y --poll y $vg || ret=$?
+           action "Starting monitoring for VG $vg:" $VGCHANGE --monitor y --poll y --config 'log{command_names=0 prefix="  "}' $vg || ret=$?
        done
 
        return $ret
@@ -65,10 +66,10 @@ stop()
           echo "Not stopping monitoring, this is a dangerous operation. Please use force-stop to override."
           return 1
        fi
-       VGSLIST=`$VGS --noheadings -o name 2> /dev/null`
+       VGSLIST=`$VGS --noheadings -o name --config 'log{command_names=0 prefix="  "}' 2> /dev/null`
        for vg in $VGSLIST
        do
-           action "Stopping monitoring for VG $vg:" $VGCHANGE --monitor n $vg || ret=$?
+           action "Stopping monitoring for VG $vg:" $VGCHANGE --monitor n --config 'log{command_names=0 prefix="  "}' $vg || ret=$?
        done
        return $ret
 }
index 0a42f552bebc54a00fd4b24eb48ccd69526611d4..aded8d4022190bf34e7f11a409ccabbc7db9e83e 100644 (file)
@@ -31,10 +31,10 @@ start()
 {
        ret=0
        # TODO do we want to separate out already active groups only?
-       VGS=`vgs --noheadings -o name 2> /dev/null`
+       VGS=`vgs --noheadings -o name --config 'log{command_names=0 prefix="  "}' 2> /dev/null`
        for vg in $VGS
        do
-           action "Starting monitoring for VG $vg:" $VGCHANGE --monitor y $vg || ret=$?
+           action "Starting monitoring for VG $vg:" $VGCHANGE --monitor y --config 'log{command_names=0 prefix="  "}' $vg || ret=$?
        done
 
        return $ret
@@ -49,10 +49,10 @@ stop()
           echo "Not stopping monitoring, this is a dangerous operation. Please use force-stop to override."
           return 1
        fi
-       VGS=`vgs --noheadings -o name 2> /dev/null`
+       VGS=`vgs --noheadings -o name --config 'log{command_names=0 prefix="  "}' 2> /dev/null`
        for vg in $VGS
        do
-           action "Stopping monitoring for VG $vg:" $VGCHANGE --monitor n $vg || ret=$?
+           action "Stopping monitoring for VG $vg:" $VGCHANGE --monitor n --config 'log{command_names=0 prefix="  "}' $vg || ret=$?
        done
        return $ret
 }
diff --git a/scripts/lvm2_monitoring_systemd_red_hat.service.in b/scripts/lvm2_monitoring_systemd_red_hat.service.in
new file mode 100644 (file)
index 0000000..6c4c55f
--- /dev/null
@@ -0,0 +1,18 @@
+[Unit]
+Description=Monitoring of LVM2 mirrors, snapshots etc. using dmeventd or progress polling
+Documentation=man:dmeventd(8) man:lvcreate(8) man:lvchange(8) man:vgchange(8)
+Requires=dm-event.socket
+After=dm-event.socket fedora-storage-init.service fedora-storage-init-late.service lvm2-activation.service lvm2-lvmetad.service
+Before=local-fs.target
+DefaultDependencies=no
+Conflicts=shutdown.target
+
+[Service]
+Type=oneshot
+Environment=LVM_SUPPRESS_LOCKING_FAILURE_MESSAGES=1
+ExecStart=@sbindir@/lvm vgchange --monitor y
+ExecStop=@sbindir@/lvm vgchange --monitor n
+RemainAfterExit=yes
+
+[Install]
+WantedBy=sysinit.target
diff --git a/scripts/lvm2_tmpfiles_red_hat.conf.in b/scripts/lvm2_tmpfiles_red_hat.conf.in
new file mode 100644 (file)
index 0000000..1102616
--- /dev/null
@@ -0,0 +1,2 @@
+d @DEFAULT_LOCK_DIR@ 0700 root root -
+d @DEFAULT_RUN_DIR@ 0700 root root -
index 9d012d5bce334bce971c3e52294baceb99e8ef41..36034cf7cec50f7c7054dff613a452b831090d4a 100644 (file)
@@ -48,7 +48,7 @@
 #    along with this program; if not, write to the Free Software
 #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
-# $Id: lvm2create_initrd,v 1.2 2006/11/21 22:41:56 agk Exp $
+# $Id$
 
 TMPMNT=/tmp/mnt.$$
 DEVRAM=/tmp/initrd.$$
@@ -74,7 +74,7 @@ usage () {
        echo "      -e|--extra     extra files to add to initrd"
        echo "      -r|--raid      raid devices to start in initrd"
        echo "      -R|--raidconf  location of mdadm.conf file to include"
-       echo "      -M|--makedev   set MAKEDEV type (debian or redhat)"
+       echo "      -M|--makedev   set MAKEDEV type (debian, redhat, gentoo)"
 }
 
 verbose () {
@@ -379,7 +379,7 @@ redhat)
     RETCODE=$?
     ;;
 gentoo)
-    (cd $TMPMNT/dev; /usr/sbin/MAKEDEV $OPT_Q $BASICDEVICES $BLOCKDEVICES)
+    (cd $TMPMNT/dev; /sbin/MAKEDEV $OPT_Q $BASICDEVICES $BLOCKDEVICES)
     RETCODE=$?
     ;;
 *)
index c9dae9f9e83bf9430aefaee3beb25ffa96c6967e..47436780d7c2134629cba11a187ede2ce94da23f 100644 (file)
@@ -1,15 +1,7 @@
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.14
+.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
 .de Sp \" Vertical space (when we can't use .PP)
 .if t .sp .5v
 .if n .sp
 ..
 .\" Set up some character translations and predefined strings.  \*(-- will
 .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote.  | will give a
-.\" real vertical bar.  \*(C+ will give a nicer C++.  Capital omega is used to
-.\" do unbreakable dashes and therefore won't be available.  \*(C` and \*(C'
-.\" expand to `' in nroff, nothing in troff, for use with C<>.
-.tr \(*W-|\(bv\*(Tr
+.\" double quote, and \*(R" will give a right double quote.  \*(C+ will
+.\" give a nicer C++.  Capital omega is used to do unbreakable dashes and
+.\" therefore won't be available.  \*(C` and \*(C' expand to `' in nroff,
+.\" nothing in troff, for use with C<>.
+.tr \(*W-
 .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
 .ie n \{\
 .    ds -- \(*W-
 .    ds R" ''
 'br\}
 .\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\"
 .\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
 .\" entries marked with X<> in POD.  Of course, you'll have to process the
 .\" output yourself in some meaningful fashion.
-.if \nF \{\
+.ie \nF \{\
 .    de IX
 .    tm Index:\\$1\t\\n%\t"\\$2"
 ..
 .    nr % 0
 .    rr F
 .\}
-.\"
-.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
+.el \{\
+.    de IX
+..
+.\}
 .\"
 .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
 .\" Fear.  Run.  Save yourself.  No user-serviceable parts.
 .\" ========================================================================
 .\"
 .IX Title "lvm2create_initrd 8"
-.TH lvm2create_initrd 8 "2004-06-05" "lvm2create_initrd" "create LVM2 initrd"
+.TH lvm2create_initrd 8 "2011-11-12" "lvm2create_initrd" "create LVM2 initrd"
+.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
 .SH "NAME"
 lvm2create_initrd \- create initrd image for booting to root\e\-on\e\-LVM2
 .SH "SYNOPSIS"
@@ -145,10 +144,10 @@ either need a bootloader that understands \s-1LVM2\s0 volumes, or you'll need a
 filesystem on a regular volume to act as a boot partition (typically mounted
 on /boot).
 .PP
-The resulting initrd image is fairly full\-featured. It can harbor and load
+The resulting initrd image is fairly full-featured. It can harbor and load
 kernel modules, start \s-1MD\s0 devices, and boot to a shell to perform rescue
 operations.
-.Sh "Booting to your initrd Image:"
+.SS "Booting to your initrd Image:"
 .IX Subsection "Booting to your initrd Image:"
 The filesystem image created is an ext2fs filesystem, hence your kernel must have
 ext2fs built into it statically in order to boot to the image.
@@ -189,7 +188,7 @@ Specify an lvm.conf file to include in the image. This is useful if you have
 special device filters or other options you wish to use during the initrd
 stage. If this option is not
 included, then a lvm.conf file is created that contains only the current
-device filter from an \fBlvm dumpconfig\fR. This can also be set via the \fB$LVMCONF\fR
+device filter from an \fBlvm dumpconfig\fR. This can also be set via the \fB\f(CB$LVMCONF\fB\fR
 environment variable.
 .ie n .IP "\fB\-m|\-\-modules\fR ""\fI/path/to/module1.ko /path/to/module2.ko ...\fR""" 4
 .el .IP "\fB\-m|\-\-modules\fR ``\fI/path/to/module1.ko /path/to/module2.ko ...\fR''" 4
@@ -198,70 +197,80 @@ Specify modules to include and plug in during the initrd phase. This option
 takes a quoted, space-separated list of modules. Full pathnames are required.
 These modules are loaded into the kernel early in the initrd phase of the boot
 process. The current modprobe.conf file is also copied to the initrd image
-as well. This can also be specified via the \fB$MODULES\fR environment variable.
+as well. This can also be specified via the \fB\f(CB$MODULES\fB\fR environment variable.
 .ie n .IP "\fB\-e|\-\-extra\fR ""\fI/path/to/file1 /path/to/file2 ...\fR""" 4
 .el .IP "\fB\-e|\-\-extra\fR ``\fI/path/to/file1 /path/to/file2 ...\fR''" 4
 .IX Item "-e|--extra ""/path/to/file1 /path/to/file2 ..."""
 Extra files that should be included in the initrd image. These files will be
 copied to the same location in the initrd image that they are in the current
 filesystem. Again full pathnames are required. This can also be specified via
-the \fB$EXTRAFILES\fR environment variable.
+the \fB\f(CB$EXTRAFILES\fB\fR environment variable.
 .ie n .IP "\fB\-r|\-\-raid\fR ""\fI/dev/md1 /dev/md2...\fR""" 4
 .el .IP "\fB\-r|\-\-raid\fR ``\fI/dev/md1 /dev/md2...\fR''" 4
 .IX Item "-r|--raid ""/dev/md1 /dev/md2..."""
 \&\s-1RAID\s0 devices to be started prior to scanning for \s-1LVM2\s0 volume groups. If this
 option is used then then \fBmdadm\fR program must be installed. This can also be
-specified via the \fB$RAID\fR environment variable.
+specified via the \fB\f(CB$RAID\fB\fR environment variable.
 .ie n .IP "\fB\-R|\-\-raidconf\fR ""\fI/path/to/mdadm.conf\fR""" 4
 .el .IP "\fB\-R|\-\-raidconf\fR ``\fI/path/to/mdadm.conf\fR''" 4
 .IX Item "-R|--raidconf ""/path/to/mdadm.conf"""
 Location of a mdadm.conf file to include. If this is not specified, then no
 files are included, and any devices specified with the \fB\-r\fR option above
 must have minor numbers that match their superblock values. This can also be
-specified via the \fB$RAIDCONF\fR environment variable.
+specified via the \fB\f(CB$RAIDCONF\fB\fR environment variable.
 .IP "\fB\-M|\-\-makedev\fR \fIstyle\fR" 4
 .IX Item "-M|--makedev style"
-Set \s-1MAKEDEV\s0 invocation style. The script currently supports 2 styles of
-\&\s-1MAKEDEV\s0 programs \fIdebian\fR and \fIredhat\fR. The default is \fIdebian\fR. Set
-to \fIredhat\fR if using the RedHat/Fedora binary \s-1MAKEDEV\s0 program. Please send
-a bug report to maintainer if your distrib doesn't work with any of the
-current options.
+Set \s-1MAKEDEV\s0 invocation style. The script currently supports 3 styles of
+\&\s-1MAKEDEV\s0 programs \fIdebian\fR, \fIredhat\fR and \fIgentoo\fR. The default is \fIdebian\fR.
+Set to \fIredhat\fR if using the RedHat/Fedora binary \s-1MAKEDEV\s0 program. \fIgentoo\fR
+has the same binary but in /sbin instead of /dev. Please send a bug report to
+maintainer if your distribution doesn't work with any of the current options.
 .SH "ENVIRONMENT VARIABLES"
 .IX Header "ENVIRONMENT VARIABLES"
 Most of the options to this script can be set via environment variables. In
 situations where both are set, then the command-line options take precedence.
-.IP "\fB$LVMCONF\fR" 4
+.ie n .IP "\fB\fB$LVMCONF\fB\fR" 4
+.el .IP "\fB\f(CB$LVMCONF\fB\fR" 4
 .IX Item "$LVMCONF"
 Same as \-c option.
-.IP "\fB$MODULES\fR" 4
+.ie n .IP "\fB\fB$MODULES\fB\fR" 4
+.el .IP "\fB\f(CB$MODULES\fB\fR" 4
 .IX Item "$MODULES"
 Same as \-m option.
-.IP "\fB$EXTRAFILES\fR" 4
+.ie n .IP "\fB\fB$EXTRAFILES\fB\fR" 4
+.el .IP "\fB\f(CB$EXTRAFILES\fB\fR" 4
 .IX Item "$EXTRAFILES"
 Same as \-e option.
-.IP "\fB$RAID\fR" 4
+.ie n .IP "\fB\fB$RAID\fB\fR" 4
+.el .IP "\fB\f(CB$RAID\fB\fR" 4
 .IX Item "$RAID"
 Same as \-r option.
-.IP "\fB$RAIDCONF\fR" 4
+.ie n .IP "\fB\fB$RAIDCONF\fB\fR" 4
+.el .IP "\fB\f(CB$RAIDCONF\fB\fR" 4
 .IX Item "$RAIDCONF"
 Same as \-R option.
-.IP "\fB$MAKEDEV\fR" 4
+.ie n .IP "\fB\fB$MAKEDEV\fB\fR" 4
+.el .IP "\fB\f(CB$MAKEDEV\fB\fR" 4
 .IX Item "$MAKEDEV"
 Same as \-M option.
-.IP "\fB$BASICDEVICES\fR" 4
+.ie n .IP "\fB\fB$BASICDEVICES\fB\fR" 4
+.el .IP "\fB\f(CB$BASICDEVICES\fB\fR" 4
 .IX Item "$BASICDEVICES"
 Overrides the default value of \f(CW$BASICDEVICES\fR in the script (which is \*(L"std consoleonly fd\*(R"). These values are passed to the \fB\s-1MAKEDEV\s0\fR program to create device
 entries in the initrd image.
-.IP "\fB$BLOCKDEVICES\fR" 4
+.ie n .IP "\fB\fB$BLOCKDEVICES\fB\fR" 4
+.el .IP "\fB\f(CB$BLOCKDEVICES\fB\fR" 4
 .IX Item "$BLOCKDEVICES"
 Overrides the default value of \f(CW$BLOCKDEVICES\fR in the script (which is \*(L"md hda hdb hdc hdd sda sdb sdc sdd\*(R"). This value is passed to the \fB\s-1MAKEDEV\s0\fR program to
 create device entries in the initrd image.
-.IP "\fB$BINFILES\fR" 4
+.ie n .IP "\fB\fB$BINFILES\fB\fR" 4
+.el .IP "\fB\f(CB$BINFILES\fB\fR" 4
 .IX Item "$BINFILES"
 Overrides the default value of \f(CW$BINFILES\fR (which is \*(L"/lib/lvm\-200/lvm /bin/bash /bin/busybox /sbin/pivot_root\*(R"). The difference between using this and adding
 a file to the \f(CW$EXTRAFILES\fR list above is that libraries that these depend upon are also included. You can still use \f(CW$EXTRAFILES\fR to achieve the same effect, but
 you must resolve library dependencies youself.
-.IP "\fB$INITRDSIZE\fR" 4
+.ie n .IP "\fB\fB$INITRDSIZE\fB\fR" 4
+.el .IP "\fB\f(CB$INITRDSIZE\fB\fR" 4
 .IX Item "$INITRDSIZE"
 Force a particular size for your initrd image. The default is to total up the size of
 the included files and to add 512K as a buffer.
index 577930f80109e77abc0671971dfb3552bcb029f0..b25de62aca7721ab86a7757d5957df970da38ebc 100644 (file)
@@ -107,11 +107,11 @@ specified via the B<$RAIDCONF> environment variable.
 
 =item B<-M|--makedev> I<style>
 
-Set MAKEDEV invocation style. The script currently supports 2 styles of
-MAKEDEV programs I<debian> and I<redhat>. The default is I<debian>. Set
-to I<redhat> if using the RedHat/Fedora binary MAKEDEV program. Please send
-a bug report to maintainer if your distrib doesn't work with any of the
-current options.
+Set MAKEDEV invocation style. The script currently supports 3 styles of
+MAKEDEV programs I<debian>, I<redhat> and I<gentoo>. The default is I<debian>.
+Set to I<redhat> if using the RedHat/Fedora binary MAKEDEV program. I<gentoo>
+has the same binary but in /sbin instead of /dev. Please send a bug report to
+maintainer if your distribution doesn't work with any of the current options.
 
 =back
 
index 573aac1994ccbf607fc62772fdb28a1fdfbc9996..2e733cfca0b8ee7cbac4b42abe4f1a24b847dca2 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-# $Id: lvm2udev,v 1.1 2004/06/07 16:20:05 agk Exp $
+# $Id$
 
 # simple startup script to create lvm2 devices if /dev is a mountpoint, there
 # are active dm- devices, and an executable /sbin/vgscan.
index 55c477d5ee1267935012405569974889d9021577..641d109251941bf20ca1a606d8bf5b1cc21b2b4a 100755 (executable)
@@ -30,12 +30,17 @@ DD=dd
 CUT=cut
 DATE=date
 BASENAME=basename
+UDEVADM=udevadm
 UNAME=uname
+TR=tr
+SOCAT=socat # either socat or nc is needed for dumping lvmetad state
+NC=nc
 
 # user may override lvm and dmsetup location by setting LVM_BINARY
 # and DMSETUP_BINARY respectively
 LVM=${LVM_BINARY-lvm}
 DMSETUP=${DMSETUP_BINARY-dmsetup}
+LVMETAD_SOCKET=${LVM_LVMETAD_SOCKET-/var/run/lvm/lvmetad.socket}
 
 die() {
     code=$1; shift
@@ -54,15 +59,18 @@ function usage {
        echo "    -m gather LVM metadata from the PVs"
        echo "    -d <directory> dump into a directory instead of tarball"
        echo "    -c if running clvmd, gather cluster data as well"
+       echo "    -u gather udev info and context"
+       echo "    -l gather lvmetad state if running"
        echo ""
-       
+
        exit 1
 }
 
 advanced=0
 clustered=0
 metadata=0
-while getopts :acd:hm opt; do
+udev=0
+while getopts :acd:hmul opt; do
        case $opt in 
                s)      sysreport=1 ;;
                a)      advanced=1 ;;
@@ -70,13 +78,15 @@ while getopts :acd:hm opt; do
                d)      userdir=$OPTARG ;;
                h)      usage ;;
                m)      metadata=1 ;;
+               u)      udev=1 ;;
+               l)      lvmetad=1 ;;
                :)      echo "$0: $OPTARG requires a value:"; usage ;;
                \?)     echo "$0: unknown option $OPTARG"; usage ;;
                *)      usage ;;
        esac
 done
 
-NOW=`$DATE -u +%G%m%d%k%M%S | /usr/bin/tr -d ' '`
+NOW=`$DATE -u +%G%m%d%k%M%S | $TR -d ' '`
 if test -n "$userdir"; then
        dir="$userdir"
 else
@@ -116,7 +126,7 @@ if (( $advanced )); then
        myecho "Gathering LVM volume info..."
 
        myecho "  vgscan..."
-       log "\"$LVM\" vgscan -vvvv > \"$dir/vgscan\" 2>&1"
+       log "\"$LVM\" vgscan -vvvv >> \"$dir/vgscan\" 2>&1"
 
        myecho "  pvscan..."
        log "\"$LVM\" pvscan -v >> \"$dir/pvscan\" 2>> \"$log\""
@@ -125,10 +135,10 @@ if (( $advanced )); then
        log "\"$LVM\" lvs -a -o +devices >> \"$dir/lvs\" 2>> \"$log\""
 
        myecho "  pvs..."
-       log "\"$LVM\" pvs -a -v > \"$dir/pvs\" 2>> \"$log\""
+       log "\"$LVM\" pvs -a -v >> \"$dir/pvs\" 2>> \"$log\""
 
        myecho "  vgs..."
-       log "\"$LVM\" vgs -v > \"$dir/vgs\" 2>> \"$log\""
+       log "\"$LVM\" vgs -v >> \"$dir/vgs\" 2>> \"$log\""
 fi
 
 if (( $clustered )); then
@@ -166,11 +176,11 @@ if (( $clustered )); then
                echo "MASTER:"
                cat /debug/dlm/clvmd_master
        fi
-       } > $dir/cluster_info
+       } >> $dir/cluster_info
 fi
 
 myecho "Gathering LVM & device-mapper version info..."
-echo "LVM VERSION:" > "$dir/versions"
+echo "LVM VERSION:" >> "$dir/versions"
 "$LVM" lvs --version >> "$dir/versions" 2>> "$log"
 echo "DEVICE MAPPER VERSION:" >> "$dir/versions"
 "$DMSETUP" --version >> "$dir/versions" 2>> "$log"
@@ -180,24 +190,27 @@ echo "DM TARGETS VERSIONS:" >> "$dir/versions"
 "$DMSETUP" targets >> "$dir/versions" 2>> "$log"
 
 myecho "Gathering dmsetup info..."
-log "\"$DMSETUP\" info -c > \"$dir/dmsetup_info\" 2>> \"$log\""
-log "\"$DMSETUP\" table > \"$dir/dmsetup_table\" 2>> \"$log\""
-log "\"$DMSETUP\" status > \"$dir/dmsetup_status\" 2>> \"$log\""
+log "\"$DMSETUP\" info -c >> \"$dir/dmsetup_info\" 2>> \"$log\""
+log "\"$DMSETUP\" table >> \"$dir/dmsetup_table\" 2>> \"$log\""
+log "\"$DMSETUP\" status >> \"$dir/dmsetup_status\" 2>> \"$log\""
+
+# cat as workaround to avoid tty ioctl (selinux)
+log "\"$DMSETUP\" ls --tree 2>> \"$log\" | cat >> \"$dir/dmsetup_ls_tree\""
 
 myecho "Gathering process info..."
-log "$PS alx > \"$dir/ps_info\" 2>> \"$log\""
+log "$PS alx >> \"$dir/ps_info\" 2>> \"$log\""
 
 myecho "Gathering console messages..."
-log "$TAIL -n 75 /var/log/messages > \"$dir/messages\" 2>> \"$log\""
+log "$TAIL -n 75 /var/log/messages >> \"$dir/messages\" 2>> \"$log\""
 
 myecho "Gathering /etc/lvm info..."
 log "$CP -a /etc/lvm \"$dir/lvm\" 2>> \"$log\""
 
 myecho "Gathering /dev listing..."
-log "$LS -laR /dev > \"$dir/dev_listing\" 2>> \"$log\""
+log "$LS -laR /dev >> \"$dir/dev_listing\" 2>> \"$log\""
 
 myecho "Gathering /sys/block listing..."
-log "$LS -laR /sys/block > \"$dir/sysblock_listing\"  2>> \"$log\""
+log "$LS -laR /sys/block >> \"$dir/sysblock_listing\"  2>> \"$log\""
 log "$LS -laR /sys/devices/virtual/block >> \"$dir/sysblock_listing\"  2>> \"$log\""
 
 if (( $metadata )); then
@@ -218,6 +231,36 @@ if (( $metadata )); then
        done
 fi
 
+if (( $udev )); then
+       myecho "Gathering udev info..."
+
+       udev_dir="$dir/udev"
+
+       log "$MKDIR -p \"$udev_dir\""
+       log "$UDEVADM info --version >> \"$udev_dir/version\" 2>> \"$log\""
+       log "$UDEVADM info --export-db >> \"$udev_dir/db\" 2>> \"$log\""
+       log "$CP -a /etc/udev/udev.conf \"$udev_dir/conf\" 2>> \"$log\""
+       log "$LS -la /lib/udev >> \"$udev_dir/lib_dir\" 2>> \"$log\""
+       log "$CP -aR /etc/udev/rules.d \"$udev_dir/rules_etc\" 2>> \"$log\""
+       log "$CP -aR /lib/udev/rules.d \"$udev_dir/rules_lib\" 2>> \"$log\""
+fi
+
+if (( $lvmetad )); then
+    (echo 'request="dump"'; echo '##') | {
+       if type -p $SOCAT >& /dev/null; then
+           echo "$SOCAT unix-connect:$LVMETAD_SOCKET -" >> "$log"
+           $SOCAT "unix-connect:$LVMETAD_SOCKET" - 2>> "$log"
+       elif echo | $NC -U "$LVMETAD_SOCKET"; then
+           echo "$NC -U $LVMETAD_SOCKET" >> "$log"
+           $NC -U "$LVMETAD_SOCKET" 2>> "$log"
+       else
+           myecho "WARNING: Neither socat nor nc -U seems to be available." 1>&2
+           echo "# DUMP FAILED"
+           return 1
+       fi
+    } > "$dir/lvmetad.txt"
+fi
+
 if test -z "$userdir"; then
        lvm_dump="$dirbase.tgz"
        myecho "Creating report tarball in $HOME/$lvm_dump..."
@@ -232,4 +275,3 @@ if test -z "$userdir"; then
 fi
 
 exit 0
-
index 731b860efcf17b810399c295c05d559f3928f982..520ca0294395c1d4f8ac645a21ddcdb575d313c1 100755 (executable)
@@ -242,13 +242,15 @@ export FILTER="filter=[ ${FILTER} \"r|.*|\" ]"
 
 LVMCONF=${TMP_LVM_SYSTEM_DIR}/lvm.conf
 
+# FIXME convert to cmdline override
 "$LVM" dumpconfig ${LVM_OPTS} | \
 "$AWK" -v DEV=${TMP_LVM_SYSTEM_DIR} -v CACHE=${TMP_LVM_SYSTEM_DIR}/.cache \
     -v CACHE_DIR=${TMP_LVM_SYSTEM_DIR}/cache \
-    '/^[[:space:]]*filter[[:space:]]*=/{print ENVIRON["FILTER"];next} \
-     /^[[:space:]]*scan[[:space:]]*=/{print "scan = [ \"" DEV "\" ]";next} \
-     /^[[:space:]]*cache[[:space:]]*=/{print "cache = \"" CACHE "\"";next} \
-     /^[[:space:]]*cache_dir[[:space:]]*=/{print "cache_dir = \"" CACHE_DIR "\"";next} \
+    '/^[ \t]*filter[ \t]*=/{print ENVIRON["FILTER"];next} \
+     /^[ \t]*scan[ \t]*=/{print "scan = [ \"" DEV "\" ]";next} \
+     /^[ \t]*cache[ \t]*=/{print "cache = \"" CACHE "\"";next} \
+     /^[ \t]*use_lvmetad[ \t]*=/{print "use_lvmetad = 0";next} \
+     /^[ \t]*cache_dir[ \t]*=/{print "cache_dir = \"" CACHE_DIR "\"";next} \
      {print $0}' > ${LVMCONF}
 
 checkvalue $? "Failed to generate ${LVMCONF}"
@@ -282,7 +284,7 @@ checkvalue $? "PV info could not be collected without errors"
 
 # output VG info so each line looks like: name:exported?:disk1,disk2,...
 VGINFO=`echo "${PVINFO}" | \
-    "$AWK" -F : '{{sub(/^[[:space:]]*/,"")} \
+    "$AWK" -F : '{{sub(/^[ \t]*/,"")} \
     {sub(/unknown device/,"unknown_device")} \
     {vg[$2]=$1","vg[$2]} if($3 ~ /^..x/){x[$2]="x"}} \
     END{for(k in vg){printf("%s:%s:%s\n", k, x[k], vg[k])}}'`
diff --git a/test/.gitignore b/test/.gitignore
deleted file mode 100644 (file)
index 2351bfc..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-.bin-dir-stamp
-Makefile
-bin
-init.sh
index 86542c1c64881d78265331785c4b82d62e2a5434..5bbd1d6b3bca7bf5f549de3540dfb486354b1519 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2010 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2007-2012 Red Hat, Inc. All rights reserved.
 #
 # This file is part of LVM2.
 #
 
 #TEST_OPTS=--verbose --debug
 SHELL_PATH ?= $(SHELL)
-TAR ?= $(TAR)
 RM ?= rm -f
 
-subdir := $(shell pwd|sed 's,.*/,,')
+subdir = $(shell pwd|sed 's,.*/,,')
 
 srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 top_builddir = @top_builddir@
-abs_srcdir = @abs_srcdir@
-abs_builddir = @abs_builddir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
+abs_srcdir = "@abs_srcdir@"
+abs_builddir = "@abs_builddir@"
+abs_top_builddir = "@abs_top_builddir@"
+abs_top_srcdir = "@abs_top_srcdir@"
+
+SUBDIRS = api unit
+SOURCES = lib/not.c lib/harness.c
+
+include $(top_builddir)/make.tmpl
 
 T ?= .
 S ?= @ # never match anything by default
 VERBOSE ?= 0
-RUN = $(shell find $(srcdir) -regextype posix-egrep \( -name t-\*.sh -or -path */api/\*.sh \) -and -regex "$(srcdir)/.*($(T)).*" -and -not -regex "$(srcdir)/.*($(S)).*" | sort)
-RUN_BASE = $(shell echo $(RUN) | xargs -n 1 echo | sed -e s,^$(srcdir)/,,)
+ALL = $(shell find $(srcdir) \( -path \*/shell/\*.sh -or -path \*/api/\*.sh \) | sort)
+RUN = $(shell find $(srcdir) -regextype posix-egrep \( -path \*/shell/\*.sh -or -path \*/api/\*.sh \) -and -regex "$(srcdir)/.*($(T)).*" -and -not -regex "$(srcdir)/.*($(S)).*" | sort)
+RUN_BASE = $(subst $(srcdir)/,,$(RUN))
 
 # Shell quote;
 SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
 
-SUPPORT := $(srcdir)/test-utils.sh \
-           $(srcdir)/lvm-utils.sh
-
 ifeq ("@UDEV_SYNC@", "yes")
 dm_udev_synchronisation = 1
 endif
 
-all check: init.sh
-       make -C api tests
-       @echo Testing with locking_type 1
-       VERBOSE=$(VERBOSE) ./bin/harness $(RUN_BASE)
-       @echo Testing with locking_type 3
-       VERBOSE=$(VERBOSE) LVM_TEST_LOCKING=3 ./bin/harness $(RUN_BASE)
-
-check_cluster: init.sh
-       make -C api tests
+all: check
+
+help:
+       @echo -e "\nAvailable targets:"
+       @echo "  all                    Default target, run check."
+       @echo "  check                  Run all tests."
+       @echo "  check_local            Run tests without clvmd and lvmetad."
+       @echo "  check_cluster          Run tests with cluster daemon."
+       @echo "  check_lvmetad          Run tests with lvmetad daemon."
+       @echo "  clean                  Clean dir."
+       @echo "  help                   Display callable targets."
+       @echo -e "\nSupported variables:"
+       @echo "  LVM_TEST_DEVDIR        Set to '/dev' to run on real /dev."
+       @echo "  LVM_TEST_DIR           Where to create test files [TMPDIR]."
+       @echo "  LVM_TEST_LOCKING       Normal (1), Cluster (3)."
+       @echo "  LVM_TEST_LVMETAD       Start lvmetad (1)."
+       @echo "  LVM_TEST_NODEBUG       Do not debug lvm commands."
+       @echo "  LVM_TEST_PARALLEL      May skip agresive wipe of LVMTEST resources."
+       @echo "  LVM_VERIFY_UDEV        Default verify state for lvm.conf."
+       @echo "  S                      Skip given test (regex)."
+       @echo "  T                      Run given test (regex)."
+       @echo "  VERBOSE                Verbose output (1), timing (2)."
+
+check: check_local check_cluster check_lvmetad
+
+check_cluster: .tests-stamp
        @echo Testing with locking_type 3
-       VERBOSE=$(VERBOSE) LVM_TEST_LOCKING=3 ./bin/harness $(RUN_BASE)
+       VERBOSE=$(VERBOSE) LVM_TEST_LOCKING=3 ./lib/harness $(RUN_BASE)
 
-check_local: init.sh
-       make -C api tests
+check_local: .tests-stamp
        @echo Testing with locking_type 1
-       VERBOSE=$(VERBOSE) LVM_TEST_LOCKING=1 ./bin/harness $(RUN_BASE)
+       VERBOSE=$(VERBOSE) LVM_TEST_LOCKING=1 ./lib/harness $(RUN_BASE)
+
+check_lvmetad: .tests-stamp
+       @echo Testing with lvmetad on
+       VERBOSE=$(VERBOSE) LVM_TEST_LVMETAD=1 ./lib/harness $(RUN_BASE)
 
-bin/not: $(srcdir)/not.c .bin-dir-stamp
-       $(CC) -o bin/not $<
-       ln -sf not bin/should
+lib/should: lib/not
+       ln -sf not lib/should
 
-bin/harness: $(srcdir)/harness.c .bin-dir-stamp
-       $(CC) -o bin/harness $<
+lib/%: lib/%.o .lib-dir-stamp
+       $(CC) $(LDFLAGS) -o $@ $<
 
-bin/check: $(srcdir)/check.sh .bin-dir-stamp
-       cp $< bin/check
-       chmod +x bin/check
+lib/%: $(srcdir)/lib/%.sh .lib-dir-stamp
+       cp $< $@
+       chmod +x $@
 
-init.sh: $(srcdir)/Makefile.in .bin-dir-stamp bin/not bin/check bin/harness $(RUN) $(SUPPORT) $(UNIT)
-       rm -f $@-t $@
+lib/paths: $(srcdir)/Makefile.in .lib-dir-stamp
+       $(RM) $@-t
        echo 'top_srcdir=$(top_srcdir)' >> $@-t
        echo 'abs_top_builddir=$(abs_top_builddir)' >> $@-t
-       echo 'abs_top_srcdir=$(abs_top_builddir)' >> $@-t
-       echo 'PATH=$$abs_top_builddir/test/bin:$$PATH' >> $@-t
-       LDLPATH="\$$abs_top_builddir/libdm"; \
-       LDLPATH="$$LDLPATH:\$$abs_top_builddir/tools"; \
-       LDLPATH="$$LDLPATH:\$$abs_top_builddir/liblvm"; \
-       LDLPATH="$$LDLPATH:\$$abs_top_builddir/daemons/dmeventd"; \
-       LDLPATH="$$LDLPATH:\$$abs_top_builddir/daemons/dmeventd/plugins/lvm2"; \
-       LDLPATH="$$LDLPATH:\$$abs_top_builddir/daemons/dmeventd/plugins/mirror"; \
-       LDLPATH="$$LDLPATH:\$$abs_top_builddir/daemons/dmeventd/plugins/snapshot"; \
-       echo "export LD_LIBRARY_PATH=\"$$LDLPATH\"" >> $@-t
-       echo 'top_srcdir=$(top_srcdir)' >> $@-t
+       echo 'abs_top_srcdir=$(abs_top_srcdir)' >> $@-t
        echo 'abs_srcdir=$(abs_srcdir)' >> $@-t
        echo 'abs_builddir=$(abs_builddir)' >> $@-t
-       echo 'export PATH' >> $@-t
        echo 'export DM_UDEV_SYNCHRONISATION=$(dm_udev_synchronisation)' >> $@-t
-       chmod a-w $@-t
+       echo 'export THIN=@THIN@' >> $@-t
+       echo 'export LVMETAD_PIDFILE=@LVMETAD_PIDFILE@' >> $@-t
        mv $@-t $@
-       @if test "$(srcdir)" != . ; then \
-           echo "Copying tests to builddir."; \
-           cp $(SUPPORT) .; \
-           for f in $(RUN); do cp $$f `echo $$f | sed -e s,^$(srcdir)/,,`; done; \
-       fi
 
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
-       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+LIB = lib/not lib/should lib/harness \
+      lib/check lib/aux lib/test lib/utils lib/get lib/lvm-wrapper \
+      lib/paths
+
+CMDS = lvm $(shell cat $(top_builddir)/tools/.commands)
 
-.bin-dir-stamp: lvm-wrapper
-       rm -rf bin
-       mkdir bin
-       for i in lvm $$(cat ../tools/.commands); do \
-         ln -s ../lvm-wrapper bin/$$i; \
-       done
-       ln -s "$(abs_top_builddir)/tools/dmsetup" bin/dmsetup
-       ln -s "$(abs_top_builddir)/daemons/clvmd/clvmd" bin/clvmd
-       ln -s "$(abs_top_builddir)/daemons/dmeventd/dmeventd" bin/dmeventd
+.tests-stamp: $(ALL) $(LIB) $(SUBDIRS)
+       @if test "$(srcdir)" != . ; then \
+               echo "Linking tests to builddir."; \
+               $(MKDIR_P) shell; \
+               for f in $(subst $(srcdir)/,,$(ALL)); do \
+                       ln -sf $(abs_top_srcdir)/test/$$f $$f; \
+               done; \
+       fi
        touch $@
 
-lvm-wrapper: Makefile
-       rm -f $@-t $@
-       echo '#!/bin/sh'                                          >  $@-t
-       echo 'cmd=$$(echo ./$$0|sed "s,.*/,,")'                   >> $@-t
-       echo 'test "$$cmd" = lvm &&'                              >> $@-t
-       echo 'exec "$(abs_top_builddir)/tools/lvm" "$$@"'         >> $@-t
-       echo 'exec "$(abs_top_builddir)/tools/lvm" "$$cmd" "$$@"' >> $@-t
-       chmod a-w,a+x $@-t
-       mv $@-t $@
+.lib-dir-stamp:
+       $(MKDIR_P) lib
+       for i in $(CMDS); do ln -fs lvm-wrapper lib/$$i; done
+       ln -fs $(abs_top_builddir)/tools/dmsetup lib/dmsetup
+       ln -fs $(abs_top_builddir)/daemons/clvmd/clvmd lib/clvmd
+       ln -fs $(abs_top_builddir)/daemons/dmeventd/dmeventd lib/dmeventd
+       ln -fs $(abs_top_builddir)/daemons/lvmetad/lvmetad lib/lvmetad
+       ln -fs $(abs_top_srcdir)/scripts/vgimportclone.sh lib/vgimportclone
+       ln -fs $(abs_top_srcdir)/scripts/fsadm.sh lib/fsadm
+       touch $@
 
 clean:
-       rm -rf init.sh lvm-wrapper bin .bin-dir-stamp
-       if test "$(srcdir)" != . ; then rm -f $(subst $(srcdir)/, ,$(RUN)) lvm2app.sh ; fi
+       test "$(srcdir)" = . || $(RM) $(RUN_BASE)
+
+CLEAN_TARGETS += .lib-dir-stamp .tests-stamp $(LIB) $(addprefix lib/,$(CMDS)) \
+       lib/clvmd lib/dmeventd lib/dmsetup lib/lvmetad lib/fsadm lib/vgimportclone
 
-distclean: clean
-       rm -f Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 
 .NOTPARALLEL:
index b3fb7510d776d5a49a414bfc1872c2cf7f2dbbab..7ad6743532b086420da14c5f19873e6d9d0a42f6 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2009 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2009-2012 Red Hat, Inc. All rights reserved.
 #
 # This file is part of LVM2.
 #
@@ -15,47 +15,46 @@ srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 top_builddir = @top_builddir@
 
-ifeq ("@DEBUG@", "yes")
-       DEFS += -DDEBUG
-endif
-
-TARGETS = 
-test_SOURCES = test.c
-wrapper_SOURCES = test.c
-INCLUDES += -I../../include
-
-UNIT = vgtest.t percent.t
+TARGETS =
+ifeq ("@APPLIB@", "yes")
+TARGETS += test
+SOURCES = test.c
+
+TARGETS += \
+       lvtest.t \
+       percent.t \
+       pe_start.t \
+       thin_percent.t \
+       vgtest.t
+
+SOURCES2 = \
+       lvtest.c \
+       percent.c \
+       pe_start.c \
+       thin_percent.c \
+       vgtest.c
 
-LVMLIBS = @LVM2APP_LIB@ -ldevmapper
-DEPLIBS = $(top_builddir)/liblvm/liblvm2app.so $(top_builddir)/libdm/libdevmapper.so
-
-DEFS += -D_REENTRANT
+endif
 
 include $(top_builddir)/make.tmpl
 
-LDFLAGS = -L$(top_builddir)/libdm -L$(top_builddir)/liblvm
+DEFS += -D_REENTRANT
+DEPLIBS += $(top_builddir)/liblvm/liblvm2app.so $(top_builddir)/libdm/libdevmapper.so
+LDFLAGS += -L$(top_builddir)/liblvm
+LVMLIBS = @LVM2APP_LIB@ -ldevmapper
 
 ifeq ("@DMEVENTD@", "yes")
-       LVMLIBS += -ldevmapper-event
-       LDFLAGS += -L$(top_builddir)/daemons/dmeventd
+       LVMLIBS += -ldevmapper-event
+       LDFLAGS += -L$(top_builddir)/daemons/dmeventd
 endif
 
-test_OBJECTS = $(test_SOURCES:.c=.o)
-wrapper_OBJECTS = $(wrapper_SOURCES:.c=.o)
-OBJECTS = $(test_OBJECTS)
-
-all: tests test
-
-tests: $(UNIT)
-
-test: $(test_OBJECTS) $(DEPLIBS)
-       $(CC) -o test $(test_OBJECTS) $(CFLAGS) $(LDFLAGS) $(LVMLIBS) $(LIBS) $(READLINE_LIBS)
+LVMLIBS += $(LIBS)
 
 %.t: %.o $(DEPLIBS)
-       $(CC) -o $@ $(<) $(CFLAGS) $(LDFLAGS) $(LVMLIBS) $(LIBS)
+       $(CC) -o $@ $(<) $(LDFLAGS) $(LVMLIBS)
 
-wrapper: $(wrapper_OBJECTS) $(DEPLIBS)
-       $(CC) -o wrapper $(wrapper_OBJECTS) $(CFLAGS) $(LDFLAGS) $(LVMLIBS) $(LIBS) -lreadline
+test: $(OBJECTS) $(DEPLIBS)
+       $(CC) -o $@ $(OBJECTS) $(LDFLAGS) $(LVMLIBS) $(READLINE_LIBS)
 
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        cd $(top_builddir) && $(SHELL) ./config.status test/api/Makefile
diff --git a/test/api/lvtest.c b/test/api/lvtest.c
new file mode 100644 (file)
index 0000000..c0fee65
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#undef NDEBUG
+
+#include "lvm2app.h"
+#include "assert.h"
+
+#define err(args...) \
+       do { fprintf(stderr, args); goto bad; } while (0)
+
+int main(int argc, char *argv[])
+{
+       lvm_t handle;
+       vg_t vg;
+       lv_t lv;
+       int r = -1;
+
+       if (!(handle = lvm_init(NULL)))
+                return -1;
+
+       if (!(vg = lvm_vg_open(handle, argv[1], "w", 0)))
+               err("VG open %s failed.\n", argv[1]);
+
+       if (!(lv = lvm_lv_from_name(vg, "test")))
+                err("LV test not found.\n");
+
+       if (lvm_lv_deactivate(lv))
+                err("LV test deactivation failed.\n");
+
+       if (lvm_lv_activate(lv))
+                err("LV test activation failed.\n");
+
+       if (lvm_lv_activate(lv))
+                err("LV test repeated activation failed.\n");
+
+       if (lvm_lv_rename(lv, "test1"))
+               err("LV test rename to test1 failed.\n");
+
+       if (lvm_lv_rename(lv, "test2"))
+               err("LV test1 rename to test2 failed.\n");
+
+       if (lvm_lv_rename(lv, "test"))
+               err("LV test2 rename to test failed.\n");
+
+       if (lvm_vg_close(vg))
+               err("VG close failed.\n");
+
+        r = 0;
+bad:
+       lvm_quit(handle);
+       return r;
+}
diff --git a/test/api/lvtest.sh b/test/api/lvtest.sh
new file mode 100644 (file)
index 0000000..0b7684a
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh
+# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_vg 1
+
+lvcreate -n test -l 5 $vg
+aux apitest lvtest $vg
+
+check lv_field $vg/test lv_name test
diff --git a/test/api/pe_start.c b/test/api/pe_start.c
new file mode 100644 (file)
index 0000000..129f8a2
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#undef NDEBUG
+
+#include "lvm2app.h"
+#include "assert.h"
+
+int main(int argc, char *argv[])
+{
+       lvm_t handle;
+       vg_t vg = NULL;
+       pv_t pv;
+       struct lvm_property_value v;
+
+       handle = lvm_init(NULL);
+        assert(handle);
+
+       vg = lvm_vg_create(handle, argv[1]);
+        assert(vg);
+
+       if (lvm_vg_extend(vg, argv[2]))
+               abort();
+
+       pv = lvm_pv_from_name(vg, argv[2]);
+       assert(pv);
+
+        v = lvm_pv_get_property(pv, "pe_start");
+        assert(v.is_valid);
+       fprintf(stderr, "pe_start = %d\n", (int)v.value.integer);
+        assert(v.value.integer == 2048 * 512);
+
+        lvm_vg_close(vg);
+       lvm_quit(handle);
+        return 0;
+}
diff --git a/test/api/pe_start.sh b/test/api/pe_start.sh
new file mode 100644 (file)
index 0000000..20ba8ec
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh
+# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_devs 2
+
+aux apitest pe_start test_vg $dev1
+
+not vgs test_vg
+not pvs $dev1
index a3be1eb532ce80a0446f9ba9bdf5ed4342e97227..c5fa434bdf83afe8a72399fb92df4f9e3940c473 100644 (file)
  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include "lvm2app.h"
+#undef NDEBUG
 
-#define assert(x) do { if (!(x)) goto bad; } while (0)
+#include "lvm2app.h"
+#include "assert.h"
 
 int main(int argc, char *argv[])
 {
@@ -22,6 +23,7 @@ int main(int argc, char *argv[])
        vg_t vg = NULL;
        lv_t lv;
        struct lvm_property_value v;
+       struct lvm_property_value d;
 
        handle = lvm_init(NULL);
         assert(handle);
@@ -36,7 +38,7 @@ int main(int argc, char *argv[])
         assert(v.is_valid);
         assert(v.value.integer == PERCENT_0);
 
-        lv = lvm_lv_from_name(vg, "mirr");
+       lv = lvm_lv_from_name(vg, "mirr");
         assert(lv);
 
         v = lvm_lv_get_property(lv, "copy_percent");
@@ -50,15 +52,12 @@ int main(int argc, char *argv[])
         assert(v.is_valid);
         assert(v.value.integer == 50 * PERCENT_1);
 
+       d = lvm_lv_get_property(lv, "data_percent");
+       assert(d.is_valid);
+       assert(d.value.integer == v.value.integer);
+
         lvm_vg_close(vg);
-        return 0;
 
-bad:
-       if (handle && lvm_errno(handle))
-               fprintf(stderr, "LVM Error: %s\n", lvm_errmsg(handle));
-       if (vg)
-               lvm_vg_close(vg);
-       if (handle)
-               lvm_quit(handle);
-       return 1;
+       lvm_quit(handle);
+        return 0;
 }
index 4362eb271875dd931abde588d808e550e9feb484..07b8bc65527ac8f3618869c57695a1373eb70ce9 100644 (file)
@@ -1,4 +1,4 @@
-#
+#!/bin/sh
 # Copyright (C) 2010 Red Hat, Inc. All rights reserved.
 #
 # This file is part of LVM2.
 # along with this program; if not, write to the Free Software Foundation,
 # Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 
-. ./test-utils.sh
+. lib/test
+
+kernel_at_least 2 6 33 || skip
+
 aux prepare_devs 2
-vgcreate -c n -s 4k $vg $devs
-lvcreate -n foo $vg -l 5
+
+vgcreate -c n -s 4k $vg $(cat DEVICES)
+lvcreate -l 5 -n foo $vg
 lvcreate -s -n snap $vg/foo -l 2 -c 4k
 lvcreate -s -n snap2 $vg/foo -l 6 -c 4k
-dd if=/dev/urandom of=$DM_DEV_DIR/$vg/snap2 count=1 bs=1024
+dd if=/dev/urandom of="$DM_DEV_DIR/$vg/snap2" count=1 bs=1024
 lvcreate -m 1 -n mirr $vg -l 1 --mirrorlog core
-lvs
-apitest percent $vg
+lvs $vg
+aux apitest percent $vg
+
+vgremove -ff $vg
index 434baea1f3b907f70cb55a661af3116dd4a60f2a..b27aed1af7c93faf98b0fc31fcd7c2cb8a1b4578 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
  * 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 <string.h>
 #include <stdlib.h>
-#include <readline/readline.h>
+#include <ctype.h>
 
+#include "configure.h"
 #include "lvm2app.h"
 
+#ifdef READLINE_SUPPORT
+#include <readline/readline.h>
+
 #define MAX_ARGS 64
 
 static int lvm_split(char *str, int *argc, char **argv, int max)
@@ -868,6 +873,10 @@ static void _lvsegs_in_lv(char **argv, int argc)
                _print_property_value("seg_start_pe", v);
                v = lvm_lvseg_get_property(lvl->lvseg, "seg_size");
                _print_property_value("seg_size", v);
+               v = lvm_lvseg_get_property(lvl->lvseg, "devices");
+               _print_property_value("devices", v);
+               v = lvm_lvseg_get_property(lvl->lvseg, "seg_pe_ranges");
+               _print_property_value("seg_pe_ranges", v);
        }
 }
 
@@ -1071,6 +1080,13 @@ static int lvmapi_test_shell(lvm_t libh)
        free(input);
        return 0;
 }
+#else /* !READLINE_SUPPORT */
+static int lvmapi_test_shell(lvm_t libh)
+{
+       printf("Build without readline library, no interactive testing.\n");
+       return 1;
+}
+#endif
 
 int main (int argc, char *argv[])
 {
diff --git a/test/api/thin_percent.c b/test/api/thin_percent.c
new file mode 100644 (file)
index 0000000..2c8b19b
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#undef NDEBUG
+
+#include "lvm2app.h"
+#include "assert.h"
+
+int main(int argc, char *argv[])
+{
+       lvm_t handle;
+       vg_t vg;
+       lv_t lv;
+       struct lvm_property_value v;
+
+       handle = lvm_init(NULL);
+       assert(handle);
+
+       vg = lvm_vg_open(handle, argv[1], "r", 0);
+       assert(vg);
+
+       lv = lvm_lv_from_name(vg, "pool");
+       assert(lv);
+
+       v = lvm_lv_get_property(lv, "data_percent");
+       assert(v.is_valid);
+       assert(v.value.integer == 25 * PERCENT_1);
+
+
+       lv = lvm_lv_from_name(vg, "thin");
+       assert(lv);
+
+       v = lvm_lv_get_property(lv, "data_percent");
+       assert(v.is_valid);
+       assert(v.value.integer == 50 * PERCENT_1);
+
+
+       lv = lvm_lv_from_name(vg, "snap");
+       assert(lv);
+
+       v = lvm_lv_get_property(lv, "data_percent");
+       assert(v.is_valid);
+       assert(v.value.integer == 75 * PERCENT_1);
+
+       v = lvm_lv_get_property(lv, "snap_percent");
+       assert(v.is_valid);
+       assert(v.value.integer == PERCENT_INVALID);
+
+       v = lvm_lv_get_property(lv, "origin");
+       assert(v.is_valid);
+       assert(strcmp(v.value.string, "thin") == 0);
+
+       lvm_vg_close(vg);
+       lvm_quit(handle);
+
+       return 0;
+}
diff --git a/test/api/thin_percent.sh b/test/api/thin_percent.sh
new file mode 100644 (file)
index 0000000..9287cf3
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux have_thin 1 0 0 || skip
+
+# disable thin_check if not present in system
+which thin_check || aux lvmconf 'global/thin_check_executable = ""'
+
+aux prepare_devs 2
+
+vgcreate -s 64k $vg $(cat DEVICES)
+
+lvcreate -L5M -T $vg/pool
+
+lvcreate -V1M -T $vg/pool -n thin
+dd if=/dev/urandom of="$DM_DEV_DIR/$vg/thin" count=2 bs=256K
+
+lvcreate -s $vg/thin -n snap
+dd if=/dev/urandom of="$DM_DEV_DIR/$vg/snap" count=3 bs=256K
+
+lvs $vg
+
+aux apitest thin_percent $vg
+
+vgremove -ff $vg
index 35daa44e0ca2104fdbfd8eb5f633c7e6e6eaa20e..6c0be4ee87e5241cec9ec7748c5cf1b08d96e340 100644 (file)
@@ -1,3 +1,4 @@
+#!/bin/sh
 # Copyright (C) 2008 Red Hat, Inc. All rights reserved.
 #
 # This copyrighted material is made available to anyone wishing to use,
@@ -12,7 +13,8 @@
 # tests lvm2app library
 #
 
-. ./test-utils.sh
-aux prepare_devs 2
-pvcreate $dev1 $dev2
-apitest vgtest $vg1 $dev1 $dev2
+. lib/test
+
+aux prepare_pvs 2
+
+aux apitest vgtest $vg1 "$dev1" "$dev2"
diff --git a/test/check.sh b/test/check.sh
deleted file mode 100644 (file)
index 843ce86..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-#!/bin/bash
-
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-# check.sh: assert various things about volumes
-
-# USAGE
-#  check linear VG LV
-#  check lv_on VG LV PV
-
-#  check mirror VG LV [LOGDEV|core]
-#  check mirror_nonredundant VG LV
-#  check mirror_legs VG LV N
-#  check mirror_images_on VG LV DEV [DEV...]
-
-# ...
-
-set -e -o pipefail
-
-lvl() {
-       lvs -a --noheadings "$@"
-}
-
-lvdevices() {
-       lvl -odevices "$@" | sed 's/([^)]*)//g; s/,/ /g'
-}
-
-mirror_images_redundant()
-{
-  vg=$1
-  lv=$vg/$2
-
-  lvs -a $vg -o+devices
-  for i in `lvdevices $lv`; do
-         echo "# $i:"
-         lvdevices $vg/$i | sort | uniq
-  done > check.tmp.all
-
-  (grep -v ^# check.tmp.all || true) | sort | uniq -d > check.tmp
-
-  test "`cat check.tmp | wc -l`" -eq 0 || {
-         echo "mirror images of $lv expected redundant, but are not:"
-         cat check.tmp.all
-         exit 1
-  }
-}
-
-mirror_images_on() {
-       vg=$1
-       lv=$2
-
-       shift 2
-
-       for i in `lvdevices $lv`; do
-               lv_on $vg $lv $1
-               shift
-       done
-}
-
-lv_on()
-{
-       lv="$1/$2"
-       lvdevices $lv | grep -F "$3" || {
-               echo "LV $lv expected on $3 but is not:" >&2
-               lvdevices $lv >&2
-               exit 1
-       }
-       test `lvdevices $lv | grep -vF "$3" | wc -l` -eq 0 || {
-               echo "LV $lv contains unexpected devices:" >&2
-               lvdevices $lv >&2
-               exit 1
-       }
-}
-
-mirror_log_on()
-{
-       vg="$1"
-       lv="$2"
-       where="$3"
-       if test "$where" = "core"; then
-               lvl -omirror_log "$vg/$lv" | not grep mlog
-       else
-               lv_on $vg "${lv}_mlog" "$where"
-       fi
-}
-
-lv_is_contiguous()
-{
-       test `lvl --segments $1 | wc -l` -eq 1 || {
-               echo "LV $1 expected to be contiguous, but is not:"
-               lvl --segments $1
-               exit 1
-       }
-}
-
-lv_is_clung()
-{
-       test `lvdevices $1 | sort | uniq | wc -l` -eq 1 || {
-               echo "LV $1 expected to be clung, but is not:"
-               lvdevices $! | sort | uniq
-               exit 1
-       }
-}
-
-mirror_images_contiguous()
-{
-       for i in `lvdevices $1/$2`; do
-               lv_is_contiguous $1/$i
-       done
-}
-
-mirror_images_clung()
-{
-       for i in `lvdevices $1/$2`; do
-               lv_is_clung $1/$i
-       done
-}
-
-mirror() {
-       mirror_nonredundant "$@"
-       mirror_images_redundant "$1" "$2"
-}
-
-mirror_nonredundant() {
-       lv="$1/$2"
-       lvs -oattr "$lv" | grep -q "^ *m.....$" || {
-               echo "$lv expected a mirror, but is not:"
-               lvs -a $lv
-               exit 1
-       }
-       if test -n "$3"; then mirror_log_on "$1" "$2" "$3"; fi
-}
-
-mirror_legs() {
-       lv="$1/$2"
-       expect="$3"
-       lvdevices "$lv"
-       real=`lvdevices "$lv" | wc -w`
-       test "$expect" = "$real"
-}
-
-mirror_no_temporaries()
-{
-       vg=$1
-       lv=$2
-       lvl -oname $vg | grep $lv | not grep "tmp" || {
-               echo "$lv has temporary mirror images unexpectedly:"
-               lvl $vg | grep $lv
-               exit 1
-       }
-}
-
-linear() {
-       lv="$1/$2"
-       lvl -ostripes "$lv" | grep -q "1" || {
-               echo "$lv expected linear, but is not:"
-               lvl "$lv" -o+devices
-               exit 1
-       }
-}
-
-active() {
-       lv="$1/$2"
-       lvl -oattr "$lv" 2> /dev/null | grep -q "^ *....a.$" || {
-               echo "$lv expected active, but lvs says it's not:"
-               lvl "$lv" -o+devices 2>/dev/null
-               exit 1
-       }
-       dmsetup table | egrep -q "$1-$2: *[^ ]+" || {
-               echo "$lv expected active, lvs thinks it is but there are no mappings!"
-               dmsetup table | grep $1-$2:
-               exit 1
-       }
-}
-
-inactive() {
-       lv="$1/$2"
-       lvl -oattr "$lv" 2> /dev/null | grep -q '^ *....[-isd].$' || {
-               echo "$lv expected inactive, but lvs says it's not:"
-               lvl "$lv" -o+devices 2>/dev/null
-               exit 1
-       }
-       dmsetup table | not egrep -q "$1-$2: *[^ ]+" || {
-               echo "$lv expected inactive, lvs thinks it is but there are mappings!"
-               dmsetup table | grep $1-$2:
-               exit 1
-       }
-}
-
-"$@"
diff --git a/test/harness.c b/test/harness.c
deleted file mode 100644 (file)
index 0162278..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License v.2.
- *
- * 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 <fcntl.h>
-#include <string.h>
-#include <stdio.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-pid_t pid;
-int fds[2];
-
-#define MAX 1024
-
-struct stats {
-       int nfailed;
-       int nskipped;
-       int npassed;
-       int nwarned;
-       int status[MAX];
-};
-
-struct stats s;
-
-char *readbuf = NULL;
-int readbuf_sz = 0, readbuf_used = 0;
-
-int die = 0;
-int verbose = 0;
-
-#define PASSED 0
-#define SKIPPED 1
-#define FAILED 2
-#define WARNED 3
-
-void handler( int s ) {
-       signal( s, SIG_DFL );
-       kill( pid, s );
-       die = s;
-}
-
-void dump() {
-       fwrite(readbuf, 1, readbuf_used, stdout);
-}
-
-void clear() {
-       readbuf_used = 0;
-}
-
-void drain() {
-       int sz;
-       char buf[2048];
-       while (1) {
-               sz = read(fds[1], buf, 2048);
-               if (verbose)
-                       write(1, buf, sz);
-               if (sz <= 0)
-                       return;
-               if (readbuf_used + sz >= readbuf_sz) {
-                       readbuf_sz = readbuf_sz ? 2 * readbuf_sz : 4096;
-                       readbuf = realloc(readbuf, readbuf_sz);
-               }
-               if (!readbuf)
-                       exit(205);
-               memcpy(readbuf + readbuf_used, buf, sz);
-               readbuf_used += sz;
-               readbuf[readbuf_used] = 0;
-       }
-}
-
-void passed(int i, char *f) {
-       if (strstr(readbuf, "TEST WARNING")) {
-               ++s.nwarned;
-               s.status[i] = WARNED;
-               printf("warnings\n");
-       } else {
-               ++ s.npassed;
-               s.status[i] = PASSED;
-               printf("passed.\n");
-       }
-}
-
-void skipped(int i, char *f) {
-       ++ s.nskipped;
-       s.status[i] = SKIPPED;
-       printf("skipped.\n");
-}
-
-void failed(int i, char *f, int st) {
-       ++ s.nfailed;
-       s.status[i] = FAILED;
-       if(die == 2) {
-               printf("interrupted.\n");
-               return;
-       }
-       printf("FAILED.\n");
-       printf("-- FAILED %s ------------------------------------\n", f);
-       dump();
-       printf("-- FAILED %s (end) ------------------------------\n", f);
-}
-
-void run(int i, char *f) {
-       pid = fork();
-       if (pid < 0) {
-               perror("Fork failed.");
-               exit(201);
-       } else if (pid == 0) {
-               close(0);
-               dup2(fds[0], 1);
-               dup2(fds[0], 2);
-               execlp("bash", "bash", f, NULL);
-               perror("execlp");
-               fflush(stderr);
-               _exit(202);
-       } else {
-               char buf[128];
-               snprintf(buf, 128, "%s ...", f);
-               buf[127] = 0;
-               printf("Running %-40s ", buf);
-               fflush(stdout);
-               int st, w;
-               while ((w = waitpid(pid, &st, WNOHANG)) == 0) {
-                       drain();
-                       usleep(20000);
-               }
-               if (w != pid) {
-                       perror("waitpid");
-                       exit(206);
-               }
-               drain();
-               if (WIFEXITED(st)) {
-                       if (WEXITSTATUS(st) == 0) {
-                               passed(i, f);
-                       } else if (WEXITSTATUS(st) == 200) {
-                               skipped(i, f);
-                       } else {
-                               failed(i, f, st);
-                       }
-               } else {
-                       failed(i, f, st);
-               }
-               clear();
-       }
-}
-
-int main(int argc, char **argv) {
-       int i;
-
-       if (argc >= MAX) {
-               fprintf(stderr, "Sorry, my head exploded. Please increase MAX.\n");
-               exit(1);
-       }
-
-       s.nwarned = s.nfailed = s.npassed = s.nskipped = 0;
-
-       char *config = getenv("LVM_TEST_CONFIG"),
-               *config_debug,
-               *be_verbose = getenv("VERBOSE");
-       if (be_verbose && atoi(be_verbose))
-               verbose = 1; // XXX
-       config = config ? config : "";
-       asprintf(&config_debug, "%s\n%s\n", config, "log { verbose=4 }");
-
-       if (socketpair(PF_UNIX, SOCK_STREAM, 0, fds)) {
-               perror("socketpair");
-               return 201;
-       }
-
-        if ( fcntl( fds[1], F_SETFL, O_NONBLOCK ) == -1 ) {
-               perror("fcntl on socket");
-               return 202;
-       }
-
-       /* set up signal handlers */
-        for (i = 0; i <= 32; ++i) {
-            if (i == SIGCHLD || i == SIGWINCH || i == SIGURG)
-                continue;
-            signal(i, handler);
-        }
-
-       /* run the tests */
-       for (i = 1; i < argc; ++ i) {
-               run(i, argv[i]);
-               if (die)
-                       break;
-       }
-
-       printf("\n## %d tests: %d OK, %d warnings, %d failures; %d skipped\n",
-              s.nwarned + s.npassed + s.nfailed + s.nskipped,
-              s.npassed, s.nwarned, s.nfailed, s.nskipped);
-
-       /* print out a summary */
-       if (s.nfailed || s.nskipped) {
-               for (i = 1; i < argc; ++ i) {
-                       switch (s.status[i]) {
-                       case FAILED:
-                               printf("FAILED: %s\n", argv[i]);
-                               break;
-                       case SKIPPED:
-                               printf("skipped: %s\n", argv[i]);
-                               break;
-                       }
-               }
-               printf("\n");
-               return s.nfailed > 0 || die;
-       }
-       return die;
-}
diff --git a/test/harness.sh b/test/harness.sh
deleted file mode 100644 (file)
index b4bdd69..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/sh
-
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-tests="$@"
-test -z "$tests" && tests=`echo t-*.sh`
-
-for t in $tests; do
-    printf "Running %-40s" "$t ..."
-    out=`bash ./$t 2>&1`
-    ret=$?
-    if test $ret = 0; then
-       echo " passed."
-    elif test $ret = 200; then
-        skipped="$skipped $t"
-       echo " skipped."
-    else
-       echo " FAILED!"
-       len=`echo $t | wc -c`
-       # fancy formatting...
-       printf -- "--- Output: $t -"
-       for i in `seq $(($len + 14)) 78`; do echo -n "-"; done; echo
-       printf "%s\n" "$out"
-       printf -- "--- End: $t ----"
-       for i in `seq $(($len + 14)) 78`; do echo -n "-"; done; echo
-       failed="$failed $t"
-    fi
-done
-
-if test -n "$failed"; then
-    echo "Tests skipped:"
-    for t in $skipped; do
-       printf "\t%s\n" $t
-    done
-    echo "TESTS FAILED:"
-    for t in $failed; do
-       printf "\t%s\n" $t
-    done
-    exit 1
-else
-    echo "All tests passed."
-fi
diff --git a/test/lib/aux.sh b/test/lib/aux.sh
new file mode 100644 (file)
index 0000000..7c0c189
--- /dev/null
@@ -0,0 +1,551 @@
+#!/bin/bash
+# Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/utils
+
+run_valgrind() {
+       # Execute script which may use $TESTNAME for creating individual
+       # log files for each execute command
+       exec "${VALGRIND:-valg}" "$@"
+}
+
+expect_failure() {
+        echo "TEST EXPECT FAILURE"
+}
+
+prepare_clvmd() {
+       test "${LVM_TEST_LOCKING:-0}" -ne 3 && return # not needed
+
+       if pgrep clvmd ; then
+               echo "Cannot use fake cluster locking with real clvmd ($(pgrep clvmd)) running."
+               skip
+       fi
+
+       # skip if we don't have our own clvmd...
+       (which clvmd 2>/dev/null | grep "$abs_builddir") || skip
+
+       # skip if we singlenode is not compiled in
+       (clvmd --help 2>&1 | grep "Available cluster managers" | grep "singlenode") || skip
+
+#      lvmconf "activation/monitoring = 1"
+       local run_valgrind=
+       test -z "$LVM_VALGRIND_CLVMD" || run_valgrind="run_valgrind"
+       $run_valgrind lib/clvmd -Isinglenode -d 1 -f &
+       local local_clvmd=$!
+       sleep .3
+       # extra sleep for slow valgrind
+       test -z "$LVM_VALGRIND_CLVMD" || sleep 7
+       # check that it is really running now
+       ps $local_clvmd || die
+       echo $local_clvmd > LOCAL_CLVMD
+}
+
+prepare_dmeventd() {
+       if pgrep dmeventd ; then
+               echo "Cannot test dmeventd with real dmeventd ($(pgrep dmeventd)) running."
+               skip
+       fi
+
+       # skip if we don't have our own dmeventd...
+       (which dmeventd 2>/dev/null | grep "$abs_builddir") || skip
+
+       lvmconf "activation/monitoring = 1"
+
+       dmeventd -f "$@" &
+       echo $! > LOCAL_DMEVENTD
+
+       # FIXME wait for pipe in /var/run instead
+       sleep .3
+}
+
+prepare_lvmetad() {
+       # skip if we don't have our own lvmetad...
+       (which lvmetad 2>/dev/null | grep "$abs_builddir") || skip
+
+       lvmconf "global/use_lvmetad = 1"
+       lvmconf "devices/md_component_detection = 0"
+
+       local run_valgrind=
+       test -z "$LVM_VALGRIND_LVMETAD" || run_valgrind="run_valgrind"
+
+       echo "preparing lvmetad..."
+       $run_valgrind lvmetad -f "$@" -s "$TESTDIR/lvmetad.socket" -l wire,debug &
+       echo $! > LOCAL_LVMETAD
+       while ! test -e "$TESTDIR/lvmetad.socket"; do echo -n .; sleep .1; done # wait for the socket
+       echo ok
+}
+
+notify_lvmetad() {
+       if test -e LOCAL_LVMETAD; then
+               pvscan --cache "$@" || true
+       fi
+}
+
+teardown_devs_prefixed() {
+       local prefix=$1
+       local stray=${2:-0}
+       local IFS=$IFS_NL
+       local dm
+
+       # Resume suspended devices first
+       for dm in $(dm_info suspended,name | grep "^Suspended:.*$prefix"); do
+               echo "dmsetup resume \"${dm#Suspended:}\""
+               dmsetup resume "${dm#Suspended:}" || true
+       done
+
+       local mounts=( $(grep "$prefix" /proc/mounts | cut -d' ' -f1) )
+       if test ${#mounts[@]} -gt 0; then
+               test "$stray" -eq 0 || echo "Removing stray mounted devices containing $prefix: ${mounts[@]}"
+               if umount -fl "${mounts[@]}"; then
+                       udev_wait
+               fi
+       fi
+
+       # Remove devices, start with closed (sorted by open count)
+       local remfail=no
+       local need_udev_wait=0
+       init_udev_transaction
+       for dm in $(dm_info name --sort open | grep "$prefix"); do
+               dmsetup remove "$dm" &>/dev/null || remfail=yes
+               need_udev_wait=1
+       done
+       finish_udev_transaction
+       test $need_udev_wait -eq 0 || udev_wait
+
+       if test $remfail = yes; then
+               local num_devs
+               local num_remaining_devs=999
+               while num_devs=$(dm_table | grep "$prefix" | wc -l) && \
+                   test $num_devs -lt $num_remaining_devs -a $num_devs -ne 0; do
+                       test "$stray" -eq 0 || echo "Removing $num_devs stray mapped devices with names beginning with $prefix: "
+                       for dm in $(dm_info name --sort open | grep "$prefix") ; do
+                               dmsetup remove -f "$dm" || true
+                       done
+                       num_remaining_devs=$num_devs
+               done
+       fi
+}
+
+teardown_devs() {
+       # Delete any remaining dm/udev semaphores
+       teardown_udev_cookies
+
+       test -z "$PREFIX" || {
+               rm -rf "$TESTDIR/dev/$PREFIX"*
+               teardown_devs_prefixed "$PREFIX"
+       }
+
+       # NOTE: SCSI_DEBUG_DEV test must come before the LOOP test because
+       # prepare_scsi_debug_dev() also sets LOOP to short-circuit prepare_loop()
+       if test -f SCSI_DEBUG_DEV; then
+               test ${LVM_TEST_PARALLEL:-0} -eq 1 || modprobe -r scsi_debug
+       else
+               test ! -f LOOP || losetup -d $(cat LOOP) || true
+               test ! -f LOOPFILE || rm -f $(cat LOOPFILE)
+       fi
+       rm -f DEVICES # devs is set in prepare_devs()
+       rm -f LOOP
+
+       # Attempt to remove any loop devices that failed to get torn down if earlier tests aborted
+       test ${LVM_TEST_PARALLEL:-0} -eq 1 -o -z "$COMMON_PREFIX" || {
+               teardown_devs_prefixed "$COMMON_PREFIX" 1
+               local stray_loops=( $(losetup -a | grep "$COMMON_PREFIX" | cut -d: -f1) )
+               test ${#stray_loops[@]} -eq 0 || {
+                       echo "Removing stray loop devices containing $COMMON_PREFIX: ${stray_loops[@]}"
+                       losetup -d "${stray_loops[@]}"
+               }
+       }
+}
+
+teardown() {
+       echo -n "## teardown..."
+       test ! -s LOCAL_LVMETAD || \
+           (kill -TERM "$(cat LOCAL_LVMETAD)" && sleep 1 &&
+            kill -KILL "$(cat LOCAL_LVMETAD)" 2> /dev/null) || true
+
+       dm_table | not egrep -q "$vg|$vg1|$vg2|$vg3|$vg4" || {
+               # Avoid activation of dmeventd if there is no pid
+               cfg=$(test -s LOCAL_DMEVENTD || echo "--config activation{monitoring=0}")
+               vgremove -ff $cfg  \
+                       $vg $vg1 $vg2 $vg3 $vg4 &>/dev/null || rm -f debug.log
+       }
+
+       test -s LOCAL_CLVMD && {
+               kill -INT "$(cat LOCAL_CLVMD)"
+               test -z "$LVM_VALGRIND_CLVMD" || sleep 1
+               sleep .1
+               kill -9 "$(cat LOCAL_CLVMD)" &>/dev/null || true
+       }
+
+       echo -n .
+
+       pgrep dmeventd || true
+       test ! -s LOCAL_DMEVENTD || kill -9 "$(cat LOCAL_DMEVENTD)" || true
+
+       echo -n .
+
+       test -d "$DM_DEV_DIR/mapper" && teardown_devs
+
+       echo -n .
+
+       test -n "$TESTDIR" && {
+               cd "$TESTOLDPWD"
+               rm -rf "$TESTDIR" || echo BLA
+       }
+
+       echo "ok"
+
+       test ${LVM_TEST_PARALLEL:-0} -eq 1 -o -n "$RUNNING_DMEVENTD" || not pgrep dmeventd #&>/dev/null
+}
+
+make_ioerror() {
+       echo 0 10000000 error | dmsetup create -u ${PREFIX}-ioerror ioerror
+       ln -s "$DM_DEV_DIR/mapper/ioerror" "$DM_DEV_DIR/ioerror"
+}
+
+prepare_loop() {
+       local size=${1=32}
+       local i
+       local slash
+
+       test -f LOOP && LOOP=$(cat LOOP)
+       echo -n "## preparing loop device..."
+
+       # skip if prepare_scsi_debug_dev() was used
+       if test -f SCSI_DEBUG_DEV -a -f LOOP ; then
+               echo "(skipped)"
+               return 0
+       fi
+
+       test ! -e LOOP
+       test -n "$DM_DEV_DIR"
+
+       for i in 0 1 2 3 4 5 6 7; do
+               test -e "$DM_DEV_DIR/loop$i" || mknod "$DM_DEV_DIR/loop$i" b 7 $i
+       done
+
+       echo -n .
+
+       local LOOPFILE="$PWD/test.img"
+       dd if=/dev/zero of="$LOOPFILE" bs=$((1024*1024)) count=0 seek=$(($size-1)) 2> /dev/null
+       if LOOP=$(losetup -s -f "$LOOPFILE" 2>/dev/null); then
+               :
+       elif LOOP=$(losetup -f) && losetup "$LOOP" "$LOOPFILE"; then
+               # no -s support
+               :
+       else
+               # no -f support
+               # Iterate through $DM_DEV_DIR/loop{,/}{0,1,2,3,4,5,6,7}
+               for slash in '' /; do
+                       for i in 0 1 2 3 4 5 6 7; do
+                               local dev="$DM_DEV_DIR/loop$slash$i"
+                               ! losetup "$dev" >/dev/null 2>&1 || continue
+                               # got a free
+                               losetup "$dev" "$LOOPFILE"
+                               LOOP=$dev
+                               break
+                       done
+                       test -z "$LOOP" || break
+               done
+       fi
+       test -n "$LOOP" # confirm or fail
+       echo "$LOOP" > LOOP
+       echo "ok ($LOOP)"
+}
+
+# A drop-in replacement for prepare_loop() that uses scsi_debug to create
+# a ramdisk-based SCSI device upon which all LVM devices will be created
+# - scripts must take care not to use a DEV_SIZE that will enduce OOM-killer
+prepare_scsi_debug_dev() {
+       local DEV_SIZE=$1
+       local SCSI_DEBUG_PARAMS=${@:2}
+
+       test -f "SCSI_DEBUG_DEV" && return 0
+       test -z "$LOOP"
+       test -n "$DM_DEV_DIR"
+
+       # Skip test if awk isn't available (required for get_sd_devs_)
+       which awk || skip
+
+       # Skip test if scsi_debug module is unavailable or is already in use
+       modprobe --dry-run scsi_debug || skip
+       lsmod | grep -q scsi_debug && skip
+
+       # Create the scsi_debug device and determine the new scsi device's name
+       # NOTE: it will _never_ make sense to pass num_tgts param;
+       # last param wins.. so num_tgts=1 is imposed
+       modprobe scsi_debug dev_size_mb=$DEV_SIZE $SCSI_DEBUG_PARAMS num_tgts=1 || skip
+       sleep 2 # allow for async Linux SCSI device registration
+
+       local DEBUG_DEV="/dev/$(grep -H scsi_debug /sys/block/*/device/model | cut -f4 -d /)"
+       test -b "$DEBUG_DEV" || return 1 # should not happen
+
+       # Create symlink to scsi_debug device in $DM_DEV_DIR
+       SCSI_DEBUG_DEV="$DM_DEV_DIR/$(basename $DEBUG_DEV)"
+       echo "$SCSI_DEBUG_DEV" > SCSI_DEBUG_DEV
+       echo "$SCSI_DEBUG_DEV" > LOOP
+       # Setting $LOOP provides means for prepare_devs() override
+       test "$LVM_TEST_DEVDIR" != "/dev" && ln -snf "$DEBUG_DEV" "$SCSI_DEBUG_DEV"
+}
+
+cleanup_scsi_debug_dev() {
+       teardown_devs
+       rm -f SCSI_DEBUG_DEV LOOP
+}
+
+prepare_devs() {
+       local n=${1:-3}
+       local devsize=${2:-34}
+       local pvname=${3:-pv}
+       local loopsz
+
+       prepare_loop $(($n*$devsize))
+       echo -n "## preparing $n devices..."
+
+       if ! loopsz=$(blockdev --getsz "$LOOP" 2>/dev/null); then
+               loopsz=$(blockdev --getsize "$LOOP" 2>/dev/null)
+       fi
+
+       local size=$(($loopsz/$n))
+       devs=
+
+       init_udev_transaction
+       for i in $(seq 1 $n); do
+               local name="${PREFIX}$pvname$i"
+               local dev="$DM_DEV_DIR/mapper/$name"
+               devs="$devs $dev"
+               echo 0 $size linear "$LOOP" $((($i-1)*$size)) > "$name.table"
+               dmsetup create -u "TEST-$name" "$name" "$name.table"
+       done
+       finish_udev_transaction
+
+       #for i in `seq 1 $n`; do
+       #       local name="${PREFIX}$pvname$i"
+       #       dmsetup info -c $name
+       #done
+       #for i in `seq 1 $n`; do
+       #       local name="${PREFIX}$pvname$i"
+       #       dmsetup table $name
+       #done
+
+       echo $devs > DEVICES
+       echo "ok"
+}
+
+disable_dev() {
+       local dev
+
+       init_udev_transaction
+       for dev in "$@"; do
+               maj=$(($(stat --printf=0x%t "$dev")))
+               min=$(($(stat --printf=0x%T "$dev")))
+               echo "Disabling device $dev ($maj:$min)"
+               dmsetup remove -f "$dev" || true
+               notify_lvmetad --major "$maj" --minor "$min"
+       done
+       finish_udev_transaction
+}
+
+enable_dev() {
+       local dev
+
+       init_udev_transaction
+       for dev in "$@"; do
+               local name=$(echo "$dev" | sed -e 's,.*/,,')
+               dmsetup create -u "TEST-$name" "$name" "$name.table" || \
+                       dmsetup load "$name" "$name.table"
+               # using device name (since device path does not exists yes with udev)
+               dmsetup resume "$name"
+               notify_lvmetad "$dev"
+       done
+       finish_udev_transaction
+}
+
+backup_dev() {
+       local dev
+
+       for dev in "$@"; do
+               dd if="$dev" of="$dev.backup" bs=1024
+       done
+}
+
+restore_dev() {
+       local dev
+
+       for dev in "$@"; do
+               test -e "$dev.backup" || \
+                       die "Internal error: $dev not backed up, can't restore!"
+               dd of="$dev" if="$dev.backup" bs=1024
+       done
+}
+
+prepare_pvs() {
+       prepare_devs "$@"
+       pvcreate -ff $devs
+}
+
+prepare_vg() {
+       teardown_devs
+
+       prepare_pvs "$@"
+       vgcreate -c n $vg $devs
+}
+
+lvmconf() {
+       LVM_TEST_LOCKING=${LVM_TEST_LOCKING:-1}
+       if test "$DM_DEV_DIR" = "/dev"; then
+           LVM_VERIFY_UDEV=${LVM_VERIFY_UDEV:-0}
+       else
+           LVM_VERIFY_UDEV=${LVM_VERIFY_UDEV:-1}
+       fi
+       test -f CONFIG_VALUES || {
+            cat > CONFIG_VALUES <<-EOF
+devices/dir = "$DM_DEV_DIR"
+devices/scan = "$DM_DEV_DIR"
+devices/filter = [ "a|$DM_DEV_DIR/mirror|", "a|$DM_DEV_DIR/mapper/.*pv[0-9_]*$|", "r|.*|" ]
+devices/cache_dir = "$TESTDIR/etc"
+devices/sysfs_scan = 0
+devices/default_data_alignment = 1
+devices/md_component_detection  = 0
+log/syslog = 0
+log/indent = 1
+log/level = 9
+log/file = "$TESTDIR/debug.log"
+log/overwrite = 1
+log/activation = 1
+log/verbose = 0
+activation/retry_deactivation = 1
+backup/backup = 0
+backup/archive = 0
+global/abort_on_internal_errors = 1
+global/detect_internal_vg_cache_corruption = 1
+global/library_dir = "$TESTDIR/lib"
+global/locking_dir = "$TESTDIR/var/lock/lvm"
+global/locking_type=$LVM_TEST_LOCKING
+global/si_unit_consistency = 1
+global/fallback_to_local_locking = 0
+activation/checks = 1
+activation/udev_sync = 1
+activation/udev_rules = 1
+activation/verify_udev_operations = $LVM_VERIFY_UDEV
+activation/polling_interval = 0
+activation/snapshot_autoextend_percent = 50
+activation/snapshot_autoextend_threshold = 50
+activation/monitoring = 0
+EOF
+       }
+
+       local v
+       for v in "$@"; do
+           echo "$v" >> CONFIG_VALUES
+       done
+
+       rm -f CONFIG
+       local s
+       for s in $(cat CONFIG_VALUES | cut -f1 -d/ | sort | uniq); do
+               echo "$s {" >> CONFIG
+               local k
+               for k in $(grep ^"$s"/ CONFIG_VALUES | cut -f1 -d= | sed -e 's, *$,,' | sort | uniq); do
+                       grep "^$k" CONFIG_VALUES | tail -n 1 | sed -e "s,^$s/,    ," >> CONFIG
+               done
+               echo "}" >> CONFIG
+               echo >> CONFIG
+       done
+       mv -f CONFIG etc/lvm.conf
+}
+
+apitest() {
+       local t=$1
+       shift
+       test -x "$abs_top_builddir/test/api/$t.t" || skip
+       "$abs_top_builddir/test/api/$t.t" "$@" && rm -f debug.log
+}
+
+api() {
+       test -x "$abs_top_builddir/test/api/wrapper" || skip
+       "$abs_top_builddir/test/api/wrapper" "$@" && rm -f debug.log
+}
+
+udev_wait() {
+       pgrep udev >/dev/null || return 0
+       which udevadm >/dev/null || return 0
+       if test -n "$1" ; then
+               udevadm settle --exit-if-exists="$1" || true
+       else
+               udevadm settle --timeout=15 || true
+       fi
+}
+
+# wait_for_sync <VG/LV>
+wait_for_sync() {
+       local i
+       for i in {1..500} ; do
+               check in_sync $1 $2 && return
+               sleep .2
+       done
+
+       echo "Sync is taking too long - assume stuck"
+       return 1
+}
+
+#
+# Check wheter kernel [dm module] target exist
+# at least in expected version
+#
+# [dm-]target-name major minor revision
+#
+# i.e.   dm_target_at_least  dm-thin-pool  1 0
+target_at_least()
+{
+       case "$1" in
+         dm-*) modprobe "$1" || true ;;
+       esac
+
+       local version=$(dmsetup targets 2>/dev/null | grep "${1##dm-} " 2>/dev/null)
+       version=${version##* v}
+       shift
+
+       local major=$(echo "$version" | cut -d. -f1)
+       test -z "$1" && return 0
+       test -n "$major" || return 1
+       test "$major" -gt "$1" && return 0
+       test "$major" -eq "$1" || return 1
+
+       test -z "$2" && return 0
+       local minor=$(echo "$version" | cut -d. -f2)
+       test -n "$minor" || return 1
+       test "$minor" -gt "$2" && return 0
+       test "$minor" -eq "$2" || return 1
+
+       test -z "$3" && return 0
+       local revision=$(echo "$version" | cut -d. -f3)
+       test "$revision" -ge "$3" 2>/dev/null || return 1
+}
+
+have_thin()
+{
+       target_at_least dm-thin-pool "$@" || exit 1
+       test "$THIN" = shared || test "$THIN" = internal || exit 1
+
+       # disable thin_check if not present in system
+       which thin_check || lvmconf 'global/thin_check_executable = ""'
+}
+
+# check if lvm shell is build-in  (needs readline)
+have_readline()
+{
+       echo version | lvm &>/dev/null
+}
+
+test -f DEVICES && devs=$(cat DEVICES)
+
+#unset LVM_VALGRIND
+"$@"
diff --git a/test/lib/check.sh b/test/lib/check.sh
new file mode 100644 (file)
index 0000000..6b7849f
--- /dev/null
@@ -0,0 +1,282 @@
+#!/bin/bash
+# Copyright (C) 2010-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# check.sh: assert various things about volumes
+
+# USAGE:
+#  check linear VG LV
+#  check lv_on VG LV PV
+
+#  check mirror VG LV [LOGDEV|core]
+#  check mirror_nonredundant VG LV
+#  check mirror_legs VG LV N
+#  check mirror_images_on VG LV DEV [DEV...]
+
+# ...
+
+test -z "$BASH" || set -e -o pipefail
+
+die() {
+       echo "$@" >&2
+       return 1
+}
+
+lvl() {
+       lvs -a --noheadings "$@"
+}
+
+lvdevices() {
+       get lv_devices "$@"
+}
+
+mirror_images_redundant() {
+       local vg=$1
+       local lv=$vg/$2
+       lvs -a $vg -o+devices
+       for i in $(lvdevices $lv); do
+               echo "# $i:"
+               lvdevices $vg/$i | sort | uniq
+       done > check.tmp.all
+
+       (grep -v ^# check.tmp.all || true) | sort | uniq -d > check.tmp
+
+       test $(cat check.tmp | wc -l) -eq 0 || \
+               die "mirror images of $lv expected redundant, but are not:" \
+                       $(cat check.tmp.all)
+}
+
+lv_on() {
+       local lv=$1/$2
+       (lvdevices $lv | grep -F "$3") || \
+               die "LV $lv expected on $3 but is not:" \
+                       $(lvdevices $lv)
+       test $(lvdevices $lv | grep -vF "$3" | wc -l) -eq 0 || \
+               die "LV $lv contains unexpected devices:" \
+                       $(lvdevices $lv)
+}
+
+mirror_images_on() {
+       local vg=$1
+       local lv=$2
+       shift 2
+       for i in $(lvdevices $lv); do
+               lv_on $vg $lv $1
+               shift
+       done
+}
+
+mirror_log_on() {
+       local vg=$1
+       local lv=$2
+       local where=$3
+       if test "$where" = "core"; then
+               get lv_field $vg/$lv mirror_log | not grep mlog
+       else
+               lv_on $vg ${lv}_mlog "$where"
+       fi
+}
+
+lv_is_contiguous() {
+       local lv=$1/$2
+       test $(lvl --segments $lv | wc -l) -eq 1 || \
+               die "LV $lv expected to be contiguous, but is not:" \
+                       $(lvl --segments $lv)
+}
+
+lv_is_clung() {
+       local lv=$1/$2
+       test $(lvdevices $lv | sort | uniq | wc -l) -eq 1 || \
+               die "LV $lv expected to be clung, but is not:" \
+                       $(lvdevices $lv | sort | uniq)
+}
+
+mirror_images_contiguous() {
+       for i in $(lvdevices $1/$2); do
+               lv_is_contiguous $1 $i
+       done
+}
+
+mirror_images_clung() {
+       for i in $(lvdevices $1/$2); do
+               lv_is_clung $1 $i
+       done
+}
+
+mirror() {
+       mirror_nonredundant "$@"
+       mirror_images_redundant $1 $2
+}
+
+mirror_nonredundant() {
+       local lv=$1/$2
+       local attr=$(get lv_field $lv attr)
+       (echo "$attr" | grep "^m........$" >/dev/null) || {
+               if (echo "$attr" | grep "^o........$" >/dev/null) &&
+                  lvs -a | fgrep "[${2}_mimage" >/dev/null; then
+                       echo "TEST WARNING: $lv is a snapshot origin and looks like a mirror,"
+                       echo "assuming it is actually a mirror"
+               else
+                       die "$lv expected a mirror, but is not:" \
+                               $(lvs $lv)
+               fi
+       }
+       test -z "$3" || mirror_log_on $1 $2 "$3"
+}
+
+mirror_legs() {
+       local expect=$3
+       test "$expect" -eq $(lvdevices $1/$2 | wc -w)
+}
+
+mirror_no_temporaries() {
+       local vg=$1
+       local lv=$2
+       (lvl -o name $vg | grep $lv | not grep "tmp") || \
+               die "$lv has temporary mirror images unexpectedly:" \
+                       $(lvl $vg | grep $lv)
+}
+
+linear() {
+       local lv=$1/$2
+       test $(get lv_field $lv stripes -a) -eq 1 || \
+               die "$lv expected linear, but is not:" \
+                       $(lvl $lv -o+devices)
+}
+
+# in_sync <VG> <LV>
+# Works for "mirror" and "raid*"
+in_sync() {
+       local a
+       local b
+       local idx
+       local type
+       local lvm_name="$1/$2"
+       local dm_name=$(echo $lvm_name | sed s:-:--: | sed s:/:-:)
+
+       if ! a=(`dmsetup status $dm_name`); then
+               die "Unable to get sync status of $1"
+       elif [ ${a[2]} = "snapshot-origin" ]; then
+               if ! a=(`dmsetup status ${dm_name}-real`); then
+                       die "Unable to get sync status of $1"
+               fi
+       fi
+
+       if [ ${a[2]} = "raid" ]; then
+               # Last argument is the sync ratio for RAID
+               idx=$((${#a[@]} - 1))
+               type=${a[3]}
+       elif [ ${a[2]} = "mirror" ]; then
+               # 4th Arg tells us how far to the sync ratio
+               idx=$((${a[3]} + 4))
+               type=${a[2]}
+       else
+               die "Unable to get sync ratio for target type '${a[2]}'"
+       fi
+
+       b=( $(echo ${a[$idx]} | sed s:/:' ':) )
+
+       if [ ${b[0]} != ${b[1]} ]; then
+               echo "$lvm_name ($type) is not in-sync"
+               return 1
+       fi
+
+       if [[ ${a[$(($idx - 1))]} =~ a ]]; then
+               die "$lvm_name in-sync, but 'a' characters in health status"
+       fi
+
+       echo "$lvm_name ($type) is in-sync"
+       return 0
+}
+
+active() {
+       local lv=$1/$2
+       (get lv_field $lv attr | grep "^....a....$" >/dev/null) || \
+               die "$lv expected active, but lvs says it's not:" \
+                       $(lvl $lv -o+devices)
+       dmsetup info $1-$2 >/dev/null ||
+               die "$lv expected active, lvs thinks it is but there are no mappings!"
+}
+
+inactive() {
+       local lv=$1/$2
+       (get lv_field $lv attr | grep "^....[-isd]....$" >/dev/null) || \
+               die "$lv expected inactive, but lvs says it's not:" \
+                       $(lvl $lv -o+devices)
+       not dmsetup info $1-$2 2>/dev/null || \
+               die "$lv expected inactive, lvs thinks it is but there are mappings!" 
+}
+
+# Check for list of LVs from given VG
+lv_exists() {
+       local vg=$1
+       local lv=
+       while [ $# -gt 1 ]; do
+               shift
+               lv="$lv $vg/$1"
+       done
+       lvl $lv &>/dev/null || \
+               die "$lv expected to exist but does not"
+}
+
+pv_field() {
+       local actual=$(get pv_field "$1" "$2" "${@:4}")
+       test "$actual" = "$3" || \
+               die "pv_field: PV=\"$1\", field=\"$2\", actual=\"$actual\", expected=\"$3\""
+}
+
+vg_field() {
+       local actual=$(get vg_field $1 "$2" "${@:4}")
+       test "$actual" = "$3" || \
+               die "vg_field: vg=$1, field=\"$2\", actual=\"$actual\", expected=\"$3\""
+}
+
+lv_field() {
+       local actual=$(get lv_field $1 "$2" "${@:4}")
+       test "$actual" = "$3" || \
+               die "lv_field: lv=$lv, field=\"$2\", actual=\"$actual\", expected=\"$3\""
+}
+
+compare_fields() {
+       local cmd1=$1
+       local obj1=$2
+       local field1=$3
+       local cmd2=$4
+       local obj2=$5
+       local field2=$6
+       local val1=$($cmd1 --noheadings -o "$field1" "$obj1")
+       local val2=$($cmd2 --noheadings -o "$field2" "$obj2")
+       test "$val1" = "$val2" || \
+               die "compare_fields $obj1($field1): $val1 $obj2($field2): $val2"
+}
+
+compare_vg_field() {
+       local vg1=$1
+       local vg2=$2
+       local field=$3
+       local val1=$(vgs --noheadings -o "$field" $vg1)
+       local val2=$(vgs --noheadings -o "$field" $vg2)
+       test "$val1" = "$val2" || \
+               die "compare_vg_field: $vg1: $val1, $vg2: $val2"
+}
+
+pvlv_counts() {
+       local local_vg=$1
+       local num_pvs=$2
+       local num_lvs=$3
+       local num_snaps=$4
+       lvs -o+devices $local_vg
+       vg_field $local_vg pv_count $num_pvs
+       vg_field $local_vg lv_count $num_lvs
+       vg_field $local_vg snap_count $num_snaps
+}
+
+unset LVM_VALGRIND
+"$@"
diff --git a/test/lib/get.sh b/test/lib/get.sh
new file mode 100644 (file)
index 0000000..4197f47
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/sh
+# Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# get.sh: get various values from volumes
+#
+# USAGE:
+#  get pv_field PV field [pvs params]
+#  get vg_field VG field [vgs params]
+#  get lv_field LV field [lvs params]
+#
+#  get lv_devices LV     [lvs params]
+
+
+# trims only leading prefix, we should not need trim trailing spaces
+trim_() {
+       #local var=${var%"${var##*[! ]}"}  # remove trailing space characters
+       echo ${1#"${1%%[! ]*}"} # remove leading space characters
+}
+
+pv_field() {
+       trim_ "$(pvs --noheadings -o $2 ${@:3} $1)"
+}
+
+vg_field() {
+       trim_ "$(vgs --noheadings -o $2 ${@:3} $1)"
+}
+
+lv_field() {
+       trim_ "$(lvs --noheadings -o $2 ${@:3} $1)"
+}
+
+lv_devices() {
+       lv_field $1 devices -a "${@:2}" | sed 's/([^)]*)//g; s/,/ /g'
+}
+
+unset LVM_VALGRIND
+"$@"
diff --git a/test/lib/harness.c b/test/lib/harness.c
new file mode 100644 (file)
index 0000000..929bfc8
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2010-2012 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * 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
+ */
+
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+
+static pid_t pid;
+static int fds[2];
+
+#define MAX 1024
+
+struct stats {
+       int nfailed;
+       int nskipped;
+       int npassed;
+       int nknownfail;
+       int nwarned;
+       int status[MAX];
+};
+
+static struct stats s;
+
+static char *readbuf = NULL;
+static int readbuf_sz = 0, readbuf_used = 0;
+
+static int die = 0;
+static int verbose = 0; /* >1 with timestamps */
+static int interactive = 0; /* disable all redirections */
+
+struct subst {
+       const char *key;
+       char *value;
+};
+
+static struct subst subst[2];
+
+#define PASSED 0
+#define SKIPPED 1
+#define FAILED 2
+#define WARNED 3
+#define KNOWNFAIL 4
+
+static void handler( int sig ) {
+       signal( sig, SIG_DFL );
+       kill( pid, sig );
+       die = sig;
+}
+
+static int outline(char *buf, int start, int force) {
+       char *from = buf + start;
+       char *next = strchr(buf + start, '\n');
+
+       if (!next && !force) /* not a complete line yet... */
+               return start;
+
+       if (!next)
+               next = from + strlen(from);
+       else
+               ++next;
+
+       if (!strncmp(from, "@TESTDIR=", 9)) {
+               subst[0].key = "@TESTDIR@";
+               subst[0].value = strndup(from + 9, next - from - 9 - 1);
+       } else if (!strncmp(from, "@PREFIX=", 8)) {
+               subst[1].key = "@PREFIX@";
+               subst[1].value = strndup(from + 8, next - from - 8 - 1);
+       } else {
+               char *line = strndup(from, next - from);
+               char *a = line, *b;
+               do {
+                       int idx = -1;
+                       int i;
+                       b = line + strlen(line);
+                       for ( i = 0; i < 2; ++i ) {
+                               if (subst[i].key) {
+                                       // printf("trying: %s -> %s\n", subst[i].value, subst[i].key);
+                                       char *stop = strstr(a, subst[i].value);
+                                       if (stop && stop < b) {
+                                               idx = i;
+                                               b = stop;
+                                       }
+                               }
+                       }
+                       fwrite(a, 1, b - a, stdout);
+                       a = b;
+
+                       if ( idx >= 0 ) {
+                               fprintf(stdout, "%s", subst[idx].key);
+                               a += strlen(subst[idx].value);
+                       }
+               } while (b < line + strlen(line));
+               free(line);
+       }
+
+       return next - buf + (force ? 0 : 1);
+}
+
+static void dump(void) {
+       int counter_last = -1, counter = 0;
+
+       while ( counter < readbuf_used && counter != counter_last ) {
+               counter_last = counter;
+               counter = outline( readbuf, counter, 1 );
+       }
+}
+
+static void trickle(void) {
+       static int counter_last = -1, counter = 0;
+
+       if (counter_last > readbuf_used) {
+               counter_last = -1;
+               counter = 0;
+       }
+       while ( counter < readbuf_used && counter != counter_last ) {
+               counter_last = counter;
+               counter = outline( readbuf, counter, 1 );
+       }
+}
+
+static void clear(void) {
+       readbuf_used = 0;
+}
+
+static int64_t _get_time_us(void)
+{
+       struct timeval tv;
+
+       (void) gettimeofday(&tv, 0);
+       return (int64_t) tv.tv_sec * 1000000 + (int64_t) tv.tv_usec;
+}
+
+static void _append_buf(const char *buf, size_t len)
+{
+       if ((readbuf_used + len) >= readbuf_sz) {
+               readbuf_sz = readbuf_sz ? 2 * readbuf_sz : 4096;
+               readbuf = realloc(readbuf, readbuf_sz);
+       }
+
+       if (!readbuf)
+               exit(205);
+
+       memcpy(readbuf + readbuf_used, buf, len);
+       readbuf_used += len;
+}
+
+static const char *_append_with_stamp(const char *buf, int stamp)
+{
+       static const char spaces[] = "                 ";
+       static int64_t t_last;
+       static int64_t t_start = 0;
+       int64_t t_now;
+       char stamp_buf[32]; /* Bigger to always fit both numbers */
+       const char *be;
+       const char *bb = buf;
+       size_t len;
+
+       while ((be = strchr(bb, '\n'))) {
+               if (stamp++ == 0) {
+                       t_now = _get_time_us();
+                       if (!t_start)
+                               t_start = t_last = t_now;
+                       len = snprintf(stamp_buf, sizeof(stamp_buf),
+                                      "%8.3f%8.4f ",
+                                      (t_now - t_start) / 1000000.f,
+                                      (t_now - t_last) / 1000000.f);
+                       _append_buf(stamp_buf, (len < (sizeof(spaces) - 1)) ?
+                                   len : (sizeof(spaces) - 1));
+                       t_last = t_now;
+               }
+
+               _append_buf(bb, be + 1 - bb);
+               bb = be + 1;
+
+               if (stamp > 0 && bb[0])
+                       _append_buf(spaces, sizeof(spaces) - 1);
+       }
+
+       return bb;
+}
+
+static void drain(void) {
+       char buf[4096];
+       const char *bp;
+       int stamp = 0;
+       int sz;
+
+       while ((sz = read(fds[1], buf, sizeof(buf) - 1)) > 0) {
+               buf[sz] = '\0';
+               bp = (verbose < 2) ? buf : _append_with_stamp(buf, stamp);
+
+               if (sz > (bp - buf)) {
+                       _append_buf(bp, sz - (bp - buf));
+                       stamp = -1; /* unfinished line */
+               } else
+                       stamp = 0;
+
+               readbuf[readbuf_used] = 0;
+
+               if (verbose)
+                       trickle();
+       }
+}
+
+static const char *duration(time_t start)
+{
+       static char buf[16];
+       int t = (int)(time(NULL) - start);
+
+       sprintf(buf, "%2d:%02d", t / 60, t % 60);
+       return buf;
+}
+
+static void passed(int i, char *f, time_t t) {
+       if (readbuf && strstr(readbuf, "TEST EXPECT FAIL")) {
+               ++ s.npassed;
+               s.status[i] = PASSED;
+               printf("passed (UNEXPECTED). %s\n", duration(t));
+       } else if (readbuf && strstr(readbuf, "TEST WARNING")) {
+               ++s.nwarned;
+               s.status[i] = WARNED;
+               printf("warnings  %s\n", duration(t));
+       } else {
+               ++ s.npassed;
+               s.status[i] = PASSED;
+               printf("passed.   %s\n", duration(t));
+       }
+}
+
+static void skipped(int i, char *f) {
+       ++ s.nskipped;
+       s.status[i] = SKIPPED;
+       printf("skipped.\n");
+}
+
+static void failed(int i, char *f, int st) {
+       if (readbuf && strstr(readbuf, "TEST EXPECT FAIL")) {
+               printf("FAILED (expected).\n");
+               s.status[i] = KNOWNFAIL;
+               ++ s.nknownfail;
+               return;
+       }
+
+       ++ s.nfailed;
+       s.status[i] = FAILED;
+       if(die == 2) {
+               printf("interrupted.\n");
+               return;
+       }
+       printf("FAILED.\n");
+       if (!verbose) {
+               printf("-- FAILED %s ------------------------------------\n", f);
+               dump();
+               printf("-- FAILED %s (end) ------------------------------\n", f);
+       }
+}
+
+static void run(int i, char *f) {
+       pid = fork();
+       if (pid < 0) {
+               perror("Fork failed.");
+               exit(201);
+       } else if (pid == 0) {
+               if (!interactive) {
+                       close(0);
+                       dup2(fds[0], 1);
+                       dup2(fds[0], 2);
+                       close(fds[0]);
+                       close(fds[1]);
+               }
+               execlp("bash", "bash", f, NULL);
+               perror("execlp");
+               fflush(stderr);
+               _exit(202);
+       } else {
+               int st, w;
+               time_t start = time(NULL);
+               char buf[128];
+               snprintf(buf, 128, "%s ...", f);
+               buf[127] = 0;
+               printf("Running %-50s ", buf);
+               fflush(stdout);
+               while ((w = waitpid(pid, &st, WNOHANG)) == 0) {
+                       drain();
+                       usleep(20000);
+               }
+               if (w != pid) {
+                       perror("waitpid");
+                       exit(206);
+               }
+               drain();
+               if (WIFEXITED(st)) {
+                       if (WEXITSTATUS(st) == 0) {
+                               passed(i, f, start);
+                       } else if (WEXITSTATUS(st) == 200) {
+                               skipped(i, f);
+                       } else {
+                               failed(i, f, st);
+                       }
+               } else {
+                       failed(i, f, st);
+               }
+               clear();
+       }
+}
+
+int main(int argc, char **argv) {
+       const char *be_verbose = getenv("VERBOSE"),
+                  *be_interactive = getenv("INTERACTIVE");
+       time_t start = time(NULL);
+       int i;
+
+       if (argc >= MAX) {
+               fprintf(stderr, "Sorry, my head exploded. Please increase MAX.\n");
+               exit(1);
+       }
+
+       if (be_verbose)
+               verbose = atoi(be_verbose);
+
+       if (be_interactive)
+               interactive = atoi(be_interactive);
+
+       if (socketpair(PF_UNIX, SOCK_STREAM, 0, fds)) {
+               perror("socketpair");
+               return 201;
+       }
+
+        if ( fcntl( fds[1], F_SETFL, O_NONBLOCK ) == -1 ) {
+               perror("fcntl on socket");
+               return 202;
+       }
+
+       /* set up signal handlers */
+       for (i = 0; i <= 32; ++i) {
+               if (i == SIGCHLD || i == SIGWINCH || i == SIGURG)
+                       continue;
+               signal(i, handler);
+       }
+
+       /* run the tests */
+       for (i = 1; i < argc; ++ i) {
+               run(i, argv[i]);
+               if (die)
+                       break;
+       }
+
+       printf("\n## %d tests %s : %d OK, %d warnings, %d failures, %d known failures; %d skipped\n",
+              s.nwarned + s.npassed + s.nfailed + s.nskipped,
+              duration(start),
+              s.npassed, s.nwarned, s.nfailed, s.nknownfail, s.nskipped);
+
+       /* print out a summary */
+       if (s.nfailed || s.nskipped || s.nknownfail) {
+               for (i = 1; i < argc; ++ i) {
+                       switch (s.status[i]) {
+                       case FAILED:
+                               printf("FAILED: %s\n", argv[i]);
+                               break;
+                       case KNOWNFAIL:
+                               printf("FAILED (expected): %s\n", argv[i]);
+                               break;
+                       case SKIPPED:
+                               printf("skipped: %s\n", argv[i]);
+                               break;
+                       }
+               }
+               printf("\n");
+               return s.nfailed > 0 || die;
+       }
+
+       free(readbuf);
+
+       return die;
+}
diff --git a/test/lib/lvm-wrapper.sh b/test/lib/lvm-wrapper.sh
new file mode 100644 (file)
index 0000000..d3a2a36
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/sh
+# Copyright (C) 2011-2012 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/paths
+
+CMD=${0##*/}
+test "$CMD" != lvm || unset CMD
+
+# Multiple level of LVM_VALGRIND support
+# the higher level the more commands are traced
+if test -n "$LVM_VALGRIND"; then
+       RUN_VALGRIND="aux run_valgrind";
+       case "$CMD" in
+         lvs|pvs|vgs|vgck|vgscan)
+               test "$LVM_VALGRIND" -gt 2 || unset RUN_VALGRIND ;;
+         pvcreate|pvremove|lvremove|vgcreate|vgremove)
+               test "$LVM_VALGRIND" -gt 1 || unset RUN_VALGRIND ;;
+         *)
+               test "$LVM_VALGRIND" -gt 0 || unset RUN_VALGRIND ;;
+       esac
+fi
+
+$RUN_VALGRIND "$abs_top_builddir/tools/lvm" $CMD "$@" && \
+       rm -f debug.log # Remove log for successful command
diff --git a/test/lib/not.c b/test/lib/not.c
new file mode 100644 (file)
index 0000000..9f6b988
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * 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 <unistd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+static int finished(const char *cmd, int status) {
+       if (!strcmp(cmd, "not"))
+               return !status;
+       if (!strcmp(cmd, "should")) {
+               if (status)
+                       fprintf(stderr, "TEST WARNING: Ignoring command failure.\n");
+               return 0;
+       }
+       return 6;
+}
+
+int main(int args, char **argv) {
+       pid_t pid;
+       int status;
+       int FAILURE = 6;
+
+       if (args < 2) {
+               fprintf(stderr, "Need args\n");
+               return FAILURE;
+       }
+
+       pid = fork();
+       if (pid == -1) {
+               fprintf(stderr, "Could not fork\n");
+               return FAILURE;
+       } else if (pid == 0) {  /* child */
+               execvp(argv[1], &argv[1]);
+               /* should not be accessible */
+               return FAILURE;
+       } else {                /* parent */
+               waitpid(pid, &status, 0);
+               if (!WIFEXITED(status)) {
+                       if (WIFSIGNALED(status))
+                               fprintf(stderr,
+                                       "Process %d died of signal %d.\n",
+                                       pid, WTERMSIG(status));
+                       /* did not exit correctly */
+                       return FAILURE;
+               }
+
+               return finished(argv[0], WEXITSTATUS(status));
+       }
+       /* not accessible */
+       return FAILURE;
+}
diff --git a/test/lib/test.sh b/test/lib/test.sh
new file mode 100644 (file)
index 0000000..3729749
--- /dev/null
@@ -0,0 +1,79 @@
+#!/bin/bash
+# Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# sanitize the environment
+LANG=C
+LC_ALL=C
+TZ=UTC
+
+# Put script name into variable, so it can used in external scripts
+TESTNAME=${0##*/}
+# Nice debug message
+PS4='#${BASH_SOURCE[0]##*/}:${LINENO}+ '
+export TESTNAME PS4
+
+unset CDPATH
+
+# grab some common utilities
+. lib/utils
+
+TESTOLDPWD=$(pwd)
+COMMON_PREFIX="LVMTEST"
+PREFIX="${COMMON_PREFIX}$$"
+
+TESTDIR=$(mkdtemp "${LVM_TEST_DIR:-$TESTOLDPWD}" "$PREFIX.XXXXXXXXXX") || \
+       die "failed to create temporary directory in ${LVM_TEST_DIR:-$TESTOLDPWD}"
+RUNNING_DMEVENTD=$(pgrep dmeventd) || true
+
+export TESTOLDPWD TESTDIR COMMON_PREFIX PREFIX RUNNING_DMEVENTD
+
+test -n "$BASH" && trap 'set +vx; STACKTRACE; set -vx' ERR
+trap 'aux teardown' EXIT # don't forget to clean up
+
+DM_DEV_DIR="$TESTDIR/dev"
+LVM_SYSTEM_DIR="$TESTDIR/etc"
+mkdir "$LVM_SYSTEM_DIR" "$TESTDIR/lib" "$DM_DEV_DIR"
+if test -n "$LVM_TEST_DEVDIR" ; then
+       DM_DEV_DIR=$LVM_TEST_DEVDIR
+else
+       mknod "$DM_DEV_DIR/testnull" c 1 3 || die "mknod failed";
+       echo >"$DM_DEV_DIR/testnull" || \
+               die "Filesystem does support devices in $DM_DEV_DIR (mounted with nodev?)"
+       mkdir "$DM_DEV_DIR/mapper"
+fi
+
+export DM_DEV_DIR LVM_SYSTEM_DIR
+
+cd "$TESTDIR"
+
+echo "$TESTNAME" >TESTNAME
+
+# Setting up symlink from $i to $TESTDIR/lib
+find "$abs_top_builddir/daemons/dmeventd/plugins/" -name '*.so' \
+       -exec ln -s -t lib "{}" +
+find "$abs_top_builddir/test/lib" ! \( -name '*.sh' -o -name '*.[cdo]' \
+       -o -name '*~' \)  -exec ln -s -t lib "{}" +
+
+# Set vars from utils now that we have TESTDIR/PREFIX/...
+prepare_test_vars
+
+test -n "$BASH" && set -eE -o pipefail
+
+aux lvmconf
+aux prepare_clvmd
+test -n "$LVM_TEST_LVMETAD" && {
+       aux prepare_lvmetad
+       export LVM_LVMETAD_SOCKET="$TESTDIR/lvmetad.socket"
+}
+echo "@TESTDIR=$TESTDIR"
+echo "@PREFIX=$PREFIX"
+
+set -vx
diff --git a/test/lib/utils.sh b/test/lib/utils.sh
new file mode 100644 (file)
index 0000000..70d9f66
--- /dev/null
@@ -0,0 +1,215 @@
+#!/bin/bash
+# Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+set -e
+MAX_TRIES=4
+IFS_NL='
+'
+
+die() {
+       echo "$@" >&2
+       return 1
+}
+
+rand_bytes() {
+       n=$1
+
+       chars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+
+       dev_rand="/dev/urandom"
+       if test -r "$dev_rand"; then
+               # Note: 256-length($chars) == 194; 3 copies of $chars is 186 + 8 = 194.
+               head -c"$n" "$dev_rand" | tr -c "$chars" "01234567$chars$chars$chars"
+               return
+       fi
+
+       cmds='date; date +%N; free; who -a; w; ps auxww; ps ef; netstat -n'
+       data=$( (eval "$cmds") 2>&1 | gzip )
+
+       n_plus_50=$(expr $n + 50)
+
+       # Ensure that $data has length at least 50+$n
+       while :; do
+               len=$(echo "$data" | wc -c)
+               test $n_plus_50 -le $len && break;
+               data=$( (echo "$data"; eval "$cmds") 2>&1 | gzip )
+       done
+
+       echo "$data" | dd bs=1 skip=50 count=$n 2>/dev/null \
+               | tr -c "$chars" "01234567$chars$chars$chars"
+}
+
+mkdtemp() {
+       case $# in
+               2) ;;
+               *) die "Usage: mkdtemp DIR TEMPLATE";;
+       esac
+
+       destdir=$1
+       template=$2
+
+       case "$template" in
+               *XXXX) ;;
+               *) die "Invalid template: $template (must have a suffix of at least 4 X's)";;
+       esac
+
+       fail=0
+
+       # First, try to use mktemp.
+       d=$(env -u TMPDIR mktemp -d -t -p "$destdir" "$template" 2>/dev/null) || fail=1
+
+       # The resulting name must be in the specified directory.
+       case "$d" in "${destdir}"*);; *) fail=1;; esac
+
+       # It must have created the directory.
+       test -d "$d" || fail=1
+
+       # It must have 0700 permissions.
+       perms=$(ls -dgo "$d" 2>/dev/null) || fail=1
+       case "$perms" in drwx------*) ;; *) fail=1;; esac
+
+       test $fail = 0 && { echo "$d"; return; }
+
+       # If we reach this point, we'll have to create a directory manually.
+
+       # Get a copy of the template without its suffix of X's.
+       base_template=$(echo "$template" | sed 's/XX*$//')
+
+       # Calculate how many X's we've just removed.
+       nx=$(expr length "$template" - length "$base_template")
+
+       err=
+       i=1
+       while :; do
+               X=$(rand_bytes "$nx")
+               candidate_dir="$destdir/$base_template$X"
+               err=$(mkdir -m 0700 "$candidate_dir" 2>&1) && \
+                       { echo "$candidate_dir"; return; }
+               test $MAX_TRIES -le $i && break;
+               i=$(expr $i + 1)
+       done
+       die "$err"
+}
+
+STACKTRACE() {
+       trap - ERR
+       local i=0
+
+       echo "## - $0:${BASH_LINENO[0]}"
+       while FUNC=${FUNCNAME[$i]}; test "$FUNC" != "main"; do
+               echo "## $i ${FUNC}() called from ${BASH_SOURCE[$i]}:${BASH_LINENO[$i]}"
+               i=$(($i + 1))
+       done
+
+       test ${LVM_TEST_PARALLEL:-0} -eq 1 -o -n "$RUNNING_DMEVENTD" -o -f LOCAL_DMEVENTD || {
+               pgrep dmeventd &>/dev/null && \
+                       die "** During test dmeventd has been started!"
+       }
+
+       # Get backtraces from coredumps
+       if which gdb &>/dev/null; then
+               echo bt full > gdb_commands.txt
+               echo l >> gdb_commands.txt
+               echo quit >> gdb_commands.txt
+               for core in $(ls core* 2>/dev/null); do
+                       bin=$(gdb -batch -c "$core" 2>&1 | grep "generated by" | \
+                       sed -e "s,.*generated by \`\([^ ']*\).*,\1,")
+                       gdb -batch -c "$core" -x gdb_commands.txt $(which "$bin")
+               done
+       fi
+
+       test -z "$LVM_TEST_NODEBUG" -a -f debug.log && {
+               sed -e "s,^,## DEBUG: ,;s,$top_srcdir/\?,," < debug.log
+       }
+
+       test -f SKIP_THIS_TEST && exit 200
+}
+
+init_udev_transaction() {
+       if test "$DM_UDEV_SYNCHRONISATION" = 1; then
+               local cookie=$(dmsetup udevcreatecookie)
+               # Cookie is not generated if udev is not running!
+               test -z "$cookie" || export DM_UDEV_COOKIE=$cookie
+       fi
+}
+
+finish_udev_transaction() {
+       if test "$DM_UDEV_SYNCHRONISATION" = 1 -a -n "$DM_UDEV_COOKIE"; then
+               dmsetup udevreleasecookie
+               unset DM_UDEV_COOKIE
+       fi
+}
+
+teardown_udev_cookies() {
+       if test "$DM_UDEV_SYNCHRONISATION" = 1; then
+               # Delete any cookies created more than 10 minutes ago
+               # and not used in the last 10 minutes.
+               # Log only non-zero semaphores count
+               (dmsetup udevcomplete_all -y 10 | grep -v "^0 ") || true
+       fi
+}
+
+dm_info() {
+       should dmsetup info --noheadings -c -o "$@"
+}
+
+dm_table() {
+       should dmsetup table "$@"
+}
+
+skip() {
+       touch SKIP_THIS_TEST
+       exit 200
+}
+
+kernel_at_least() {
+       local major=$(uname -r | cut -d. -f1)
+       local minor=$(uname -r | cut -d. -f2 | cut -d- -f1)
+
+       test "$major" -gt "$1" && return 0
+       test "$major" -eq "$1" || return 1
+       test "$minor" -gt "$2" && return 0
+       test "$minor" -eq "$2" || return 1
+       test -z "$3" && return 0
+
+       local minor2=$(uname -r | cut -d. -f3 | cut -d- -f1)
+       test -z "$minor2" -a "$3" -ne 0 && return 1
+       test "$minor2" -ge "$3" 2>/dev/null || return 1
+}
+
+prepare_test_vars() {
+       vg="${PREFIX}vg"
+       lv=LV
+
+       for i in $(seq 1 16); do
+               name="${PREFIX}pv$i"
+               dev="$DM_DEV_DIR/mapper/$name"
+               eval "dev$i=\"$dev\""
+               eval "lv$i=LV$i"
+               eval "vg$i=${PREFIX}vg$i"
+       done
+}
+
+# check if $abs_top_builddir was already set via 'lib/paths'
+test -n "${abs_top_builddir+varset}" || . lib/paths || die "you must run make first"
+
+case "$PATH" in
+*"$abs_top_builddir/test/lib"*) ;;
+*)
+        PATH="$abs_top_builddir/test/lib":$PATH
+        for d in daemons/dmeventd/plugins/mirror daemons/dmeventd/plugins/snapshot \
+                daemons/dmeventd/plugins/lvm2 daemons/dmeventd liblvm tools libdm; do
+                LD_LIBRARY_PATH="$abs_top_builddir/$d":$LD_LIBRARY_PATH
+        done
+        export PATH LD_LIBRARY_PATH ;;
+esac
+
+test -z "$PREFIX" || prepare_test_vars
diff --git a/test/lvm-utils.sh b/test/lvm-utils.sh
deleted file mode 100644 (file)
index fec4e2c..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-# Put lvm-related utilities here.
-# This file is sourced from test-lib.sh.
-
-# Copyright (C) 2007, 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-export LVM_SUPPRESS_FD_WARNINGS=1
-
-ME=$(basename "$0")
-warn() { echo >&2 "$ME: $@"; }
-
-trim()
-{
-    trimmed=${1%% }
-    trimmed=${trimmed## }
-
-    echo "$trimmed"
-}
-
-compare_two_fields_()
-{
-    local cmd1=$1;
-    local obj1=$2;
-    local field1=$3;
-    local cmd2=$4;
-    local obj2=$5;
-    local field2=$6;
-    local val1;
-    local val2;
-
-    val1=$($cmd1 --noheadings -o $field1 $obj1)
-    val2=$($cmd2 --noheadings -o $field2 $obj2)
-if test "$verbose" = "t"
-then
-  echo "compare_two_fields_ $obj1($field1): $val1 $obj2($field2): $val2"
-fi
-  test "$val1" = "$val2"
-}
-
-compare_vg_field_()
-{
-    local vg1=$1;
-    local vg2=$2;
-    local field=$3;
-    local val1;
-    local val2;
-
-    val1=$(vgs --noheadings -o $field $vg1)
-    val2=$(vgs --noheadings -o $field $vg2)
-if test "$verbose" = "t"
-then
-  echo "compare_vg_field_ VG1: $val1 VG2: $val2"
-fi
-  test "$val1" = "$val2"
-}
-
-
-get_pv_field() {
-       local pv=$1
-       local field=$2
-       local value
-       pvs --noheading -o $field $pv | sed 's/^ *//'
-}
-
-get_vg_field() {
-       local vg=$1
-       local field=$2
-       local value
-       vgs --noheading -o $field $vg | sed 's/^ *//'
-}
-
-get_lv_field() {
-       local lv=$1
-       local field=$2
-       local value
-       lvs --noheading -o $field $lv | sed 's/^ *//'
-}
-
-check_vg_field_()
-{
-    local vg=$1;
-    local field=$2;
-    local expected=$3;
-    local actual;
-
-    actual=$(trim $(vgs --noheadings -o $field $vg))
-if test "$verbose" = "t"
-then
-  echo "check_vg_field_ VG=$vg, field=$field, actual=$actual, expected=$expected"
-fi
-  test "$actual" = "$expected"
-}
-
-check_pv_field_()
-{
-    local pv=$1;
-    local field=$2;
-    local expected=$3;
-    local pvs_args=$4; # optional
-    local actual;
-
-    actual=$(trim $(pvs --noheadings $pvs_args -o $field $pv))
-if test "$verbose" = "t"
-then
-  echo "check_pv_field_ PV=$pv, field=$field, actual=$actual, expected=$expected"
-fi
-    test "$actual" = "$expected"
-}
-
-check_lv_field_()
-{
-    local lv=$1;
-    local field=$2;
-    local expected=$3;
-    local actual;
-
-    actual=$(trim $(lvs --noheadings -o $field $lv))
-if test "$verbose" = "t"
-then
-  echo "check_lv_field_ LV=$lv, field=$field, actual=$actual, expected=$expected"
-fi
-  test "$actual" = "$expected"
-}
-
-vg_validate_pvlv_counts_()
-{
-       local local_vg=$1
-       local num_pvs=$2
-       local num_lvs=$3
-       local num_snaps=$4
-
-       lvs -a -o+devices $local_vg
-
-       check_vg_field_ $local_vg pv_count $num_pvs && \
-         check_vg_field_ $local_vg lv_count $num_lvs && \
-         check_vg_field_ $local_vg snap_count $num_snaps
-}
-
-dmsetup_has_dm_devdir_support_()
-{
-  # Detect support for the envvar.  If it's supported, the
-  # following command will fail with the expected diagnostic.
-  out=$(DM_DEV_DIR=j dmsetup version 2>&1)
-  test "$?:$out" = "1:Invalid DM_DEV_DIR envvar value." -o \
-       "$?:$out" = "1:Invalid DM_DEV_DIR environment variable value."
-}
diff --git a/test/mkdtemp b/test/mkdtemp
deleted file mode 100755 (executable)
index 89be8ac..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-#!/bin/sh
-# Create a temporary directory, sort of like mktemp -d does.
-
-# Copyright (C) 2007 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-# Written by Jim Meyering.
-
-# Usage: mkdtemp /tmp phoey.XXXXXXXXXX
-
-# First, try to use the mktemp program.
-# Failing that, we'll roll our own mktemp-like function:
-#  - try to get random bytes from /dev/urandom
-#  - failing that, generate output from a combination of quickly-varying
-#      sources and gzip.  Ignore non-varying gzip header, and extract
-#      "random" bits from there.
-#  - given those bits, map to file-name bytes using tr, and try to create
-#      the desired directory.
-#  - make only $MAX_TRIES attempts
-
-ME=$(basename "$0")
-die() { echo >&2 "$ME: $@"; exit 1; }
-
-MAX_TRIES=4
-
-rand_bytes()
-{
-  n=$1
-
-  chars=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
-
-  dev_rand=/dev/urandom
-  if test -r "$dev_rand"; then
-    # Note: 256-length($chars) == 194; 3 copies of $chars is 186 + 8 = 194.
-    head -c$n "$dev_rand" | tr -c $chars 01234567$chars$chars$chars
-    return
-  fi
-
-  cmds='date; date +%N; free; who -a; w; ps auxww; ps ef; netstat -n'
-  data=$( (eval "$cmds") 2>&1 | gzip )
-
-  n_plus_50=$(expr $n + 50)
-
-  # Ensure that $data has length at least 50+$n
-  while :; do
-    len=$(echo "$data"|wc -c)
-    test $n_plus_50 -le $len && break;
-    data=$( (echo "$data"; eval "$cmds") 2>&1 | gzip )
-  done
-
-  echo "$data" \
-    | dd bs=1 skip=50 count=$n 2>/dev/null \
-    | tr -c $chars 01234567$chars$chars$chars
-}
-
-mkdtemp()
-{
-  case $# in
-  2);;
-  *) die "Usage: $ME DIR TEMPLATE";;
-  esac
-
-  destdir=$1
-  template=$2
-
-  case $template in
-  *XXXX) ;;
-  *) die "invalid template: $template (must have a suffix of at least 4 X's)";;
-  esac
-
-  fail=0
-
-  # First, try to use mktemp.
-  d=$(env -u TMPDIR mktemp -d -t -p "$destdir" "$template" 2>/dev/null) \
-    || fail=1
-
-  # The resulting name must be in the specified directory.
-  case $d in "$destdir"*);; *) fail=1;; esac
-
-  # It must have created the directory.
-  test -d "$d" || fail=1
-
-  # It must have 0700 permissions.
-  perms=$(ls -dgo "$d" 2>/dev/null) || fail=1
-  case $perms in drwx------*) ;; *) fail=1;; esac
-
-  test $fail = 0 && {
-    echo "$d"
-    return
-  }
-
-  # If we reach this point, we'll have to create a directory manually.
-
-  # Get a copy of the template without its suffix of X's.
-  base_template=$(echo "$template"|sed 's/XX*$//')
-
-  # Calculate how many X's we've just removed.
-  nx=$(expr length "$template" - length "$base_template")
-
-  err=
-  i=1
-  while :; do
-    X=$(rand_bytes $nx)
-    candidate_dir="$destdir/$base_template$X"
-    err=$(mkdir -m 0700 "$candidate_dir" 2>&1) \
-      && { echo "$candidate_dir"; return; }
-    test $MAX_TRIES -le $i && break;
-    i=$(expr $i + 1)
-  done
-  die "$err"
-}
-
-mkdtemp "$@"
diff --git a/test/not.c b/test/not.c
deleted file mode 100644 (file)
index 534a356..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License v.2.
- *
- * 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 <unistd.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-int finished(const char *cmd, int status) {
-       if (!strcmp(cmd, "not"))
-               return !status;
-       if (!strcmp(cmd, "should")) {
-               if (status)
-                       fprintf(stderr, "TEST WARNING: Ignoring command failure.\n");
-               return 0;
-       }
-       return 6;
-}
-
-int main(int args, char **argv) {
-       pid_t pid;
-       int status;
-       int FAILURE = 6;
-
-       if (args < 2) {
-               fprintf(stderr, "Need args\n");
-               return FAILURE;
-       }
-
-       pid = fork();
-       if (pid == -1) {
-               fprintf(stderr, "Could not fork\n");
-               return FAILURE;
-       } else if (pid == 0) {  /* child */
-               execvp(argv[1], &argv[1]);
-               /* should not be accessible */
-               return FAILURE;
-       } else {                /* parent */
-               waitpid(pid, &status, 0);
-               if (!WIFEXITED(status)) {
-                       if (WIFSIGNALED(status))
-                               fprintf(stderr,
-                                       "Process %d died of signal %d.\n",
-                                       pid, WTERMSIG(status));
-                       /* did not exit correctly */
-                       return FAILURE;
-               }
-
-               return finished(argv[0], WEXITSTATUS(status));
-       }
-       /* not accessible */
-       return FAILURE;
-}
diff --git a/test/shell/000-basic.sh b/test/shell/000-basic.sh
new file mode 100644 (file)
index 0000000..83e6efe
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/sh
+# Copyright (C) 2009-2011 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+lvm version
+
+v=$abs_top_builddir/lib/misc/lvm-version.h
+sed -n "/#define LVM_VERSION ./s///p" "$v" | sed "s/ .*//" > expected
+
+lvm pvmove --version|sed -n "1s/.*: *\([0-9][^ ]*\) .*/\1/p" > actual
+
+# ensure they are the same
+diff -u actual expected
+
+# ensure we can create devices (uses dmsetup, etc)
+aux prepare_devs 5
+
+# ensure we do not crash on a bug in config file
+aux lvmconf 'log/prefix = 1""'
+not lvs $(cat DEVICES)
diff --git a/test/shell/activate-minor.sh b/test/shell/activate-minor.sh
new file mode 100644 (file)
index 0000000..5433f01
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_vg 2
+lvcreate -a n --zero n -l 1 -n foo $vg
+lvchange $vg/foo -My --major=255 --minor=123
+lvchange $vg/foo -a y
+dmsetup info $vg-foo | tee info
+egrep "^Major, minor: *[0-9]+, 123" info
diff --git a/test/shell/activate-missing-segment.sh b/test/shell/activate-missing-segment.sh
new file mode 100644 (file)
index 0000000..55ec7ec
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# Test activation behaviour with devices missing.
+# - snapshots and their origins are only activated together; if one fails, both
+#   fail
+# - partial mirrors are not activated (but maybe they should? maybe we should
+#   instead lvconvert --repair them?)
+# - linear LVs with bits missing are not activated
+
+. lib/test
+
+aux prepare_vg 2
+
+lvcreate -l100%FREE -n span $vg
+vgchange -a n $vg
+
+aux disable_dev "$dev1"
+not vgchange -a y $vg
+vgchange -a y --partial $vg
+check active $vg span
diff --git a/test/shell/activate-missing.sh b/test/shell/activate-missing.sh
new file mode 100644 (file)
index 0000000..4676ee1
--- /dev/null
@@ -0,0 +1,86 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# Test activation behaviour with devices missing.
+# - snapshots and their origins are only activated together; if one fails, both
+#   fail
+# - partial mirrors are not activated (but maybe they should? maybe we should
+#   instead lvconvert --repair them?)
+# - linear LVs with bits missing are not activated
+
+. lib/test
+
+aux prepare_vg 4
+
+lvcreate -l1 -n linear1 $vg "$dev1"
+lvcreate -l1 -n linear2 $vg "$dev2"
+lvcreate -l2 -n linear12 $vg "$dev1":4 "$dev2":4
+
+lvcreate -l1 -n origin1 $vg "$dev1"
+lvcreate -s $vg/origin1 -l1 -n s_napshot2 "$dev2"
+
+lvcreate -l1 -m1 -n mirror12 --mirrorlog core $vg "$dev1" "$dev2"
+lvcreate -l1 -m1 -n mirror123 $vg "$dev1" "$dev2" "$dev3"
+
+vgchange -a n $vg
+aux disable_dev "$dev1"
+not vgchange -a y $vg
+not vgck $vg
+
+check inactive $vg linear1
+check active $vg linear2
+check inactive $vg origin1
+check inactive $vg s_napshot2
+check inactive $vg linear12
+check inactive $vg mirror12
+check inactive $vg mirror123
+
+vgchange -a n $vg
+aux enable_dev "$dev1"
+aux disable_dev "$dev2"
+not vgchange -a y $vg
+not vgck $vg
+
+check active $vg linear1
+check inactive $vg linear2
+check inactive $vg linear12
+check inactive $vg origin1
+check inactive $vg s_napshot2
+check inactive $vg mirror12
+check inactive $vg mirror123
+
+vgchange -a n $vg
+aux enable_dev "$dev2"
+aux disable_dev "$dev3"
+not vgchange -a y $vg
+not vgck $vg
+
+check active $vg origin1
+check active $vg s_napshot2
+check active $vg linear1
+check active $vg linear2
+check active $vg linear12
+check inactive $vg mirror123
+check active $vg mirror12
+
+vgchange -a n $vg
+aux enable_dev "$dev3"
+aux disable_dev "$dev4"
+vgchange -a y $vg
+not vgck $vg
+
+check active $vg origin1
+check active $vg s_napshot2
+check active $vg linear1
+check active $vg linear2
+check active $vg linear12
+check active $vg mirror12
+check active $vg mirror123
diff --git a/test/shell/activate-partial.sh b/test/shell/activate-partial.sh
new file mode 100644 (file)
index 0000000..4a06fc1
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_vg 3
+
+lvcreate -m 1 -l 1 -n mirror $vg
+lvchange -a n $vg/mirror
+aux disable_dev "$dev1"
+
+not vgreduce --removemissing $vg
+not lvchange -v -a y $vg/mirror
+lvchange -v --partial -a y $vg/mirror
+not lvchange -v --refresh $vg/mirror
+lvchange -v --refresh --partial $vg/mirror
+
+# also check that vgchange works
+vgchange -a n --partial $vg
+vgchange -a y --partial $vg
+
+# check vgremove
+vgremove -f $vg
diff --git a/test/shell/clvmd-restart.sh b/test/shell/clvmd-restart.sh
new file mode 100644 (file)
index 0000000..2b341e5
--- /dev/null
@@ -0,0 +1,53 @@
+#!/bin/sh
+# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# set before test's clvmd is started, so it's passed in environ
+export LVM_CLVMD_BINARY=clvmd
+export LVM_BINARY=lvm
+
+. lib/test
+
+# only clvmd based test, skip otherwise
+test -e LOCAL_CLVMD || skip
+read LOCAL_CLVMD < LOCAL_CLVMD
+
+aux prepare_pvs 1
+
+vgcreate --clustered y $vg $(cat DEVICES)
+
+lvcreate -an --zero n -n $lv1 -l1 $vg
+lvcreate -an --zero n -n $lv2 -l1 $vg
+lvcreate -l1 $vg
+
+lvchange -aey $vg/$lv1
+lvchange -aey $vg/$lv2
+
+"$LVM_CLVMD_BINARY" -S
+sleep .2
+# restarted clvmd has the same PID (no fork, only execvp)
+NEW_LOCAL_CLVMD=$(pgrep clvmd)
+test "$LOCAL_CLVMD" -eq "$NEW_LOCAL_CLVMD"
+
+# try restart once more
+
+"$LVM_CLVMD_BINARY" -S
+sleep .2
+# restarted clvmd has the same PID (no fork, only execvp)
+NEW_LOCAL_CLVMD=$(pgrep clvmd)
+test "$LOCAL_CLVMD" -eq "$NEW_LOCAL_CLVMD"
+
+# FIXME: Hmm - how could we test exclusivity is preserved in singlenode ?
+lvchange -an $vg/$lv1
+lvchange -ay $vg/$lv1
+
+"$LVM_CLVMD_BINARY" -R
+
+vgremove -ff $vg
diff --git a/test/shell/covercmd.sh b/test/shell/covercmd.sh
new file mode 100644 (file)
index 0000000..b77d378
--- /dev/null
@@ -0,0 +1,102 @@
+#!/bin/sh
+# Copyright (C) 2008-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+#
+# tests basic functionality of read-ahead and ra regressions
+#
+
+. lib/test
+
+aux prepare_devs 5
+
+TEST_UUID="aaaaaa-aaaa-aaaa-aaaa-aaaa-aaaa-aaaaaa"
+
+pvcreate "$dev1"
+pvcreate --metadatacopies 0 "$dev2"
+pvcreate --metadatacopies 0 "$dev3"
+pvcreate "$dev4"
+pvcreate --norestorefile -u $TEST_UUID --metadatacopies 0 "$dev5"
+vgcreate -c n $vg $(cat DEVICES)
+lvcreate -l 5 -i5 -I256 -n $lv $vg
+
+if aux have_readline; then
+# test *scan and *display tools
+cat <<EOF | lvm
+pvscan
+vgscan
+lvscan
+lvmdiskscan
+vgdisplay --units k $vg
+lvdisplay --units g $vg
+pvdisplay -c "$dev1"
+pvdisplay -s "$dev1"
+vgdisplay -c $vg
+vgdisplay -s $vg
+lvdisplay -c $vg
+EOF
+
+for i in h b s k m g t p e H B S K M G T P E; do
+       echo pvdisplay --units $i "$dev1"
+done | lvm
+else
+pvscan
+vgscan
+lvscan
+lvmdiskscan
+vgdisplay --units k $vg
+lvdisplay --units g $vg
+pvdisplay -c "$dev1"
+pvdisplay -s "$dev1"
+vgdisplay -c $vg
+vgdisplay -s $vg
+lvdisplay -c $vg
+
+for i in h b s k m g t p e H B S K M G T P E; do
+       pvdisplay --units $i "$dev1"
+done
+fi
+
+
+# test vgexport vgimport tools
+vgchange -an $vg
+vgexport $vg
+vgimport $vg
+vgchange -ay $vg
+
+# "-persistent y --major 254 --minor 20"
+# "-persistent n"
+# test various lvm utils
+for i in dumpconfig formats segtypes; do
+       lvm $i
+done
+
+for i in pr "p rw" an ay "-monitor y" "-monitor n" \
+        -refresh "-addtag MYTAG" "-deltag MYETAG"; do
+       lvchange -$i $vg/$lv
+done
+
+pvck "$dev1"
+vgck $vg
+lvrename $vg $lv $lv-rename
+vgcfgbackup -f backup.$$ $vg
+vgchange -an $vg
+vgcfgrestore  -f backup.$$ $vg
+pvremove -y -ff "$dev5"
+not vgcfgrestore  -f backup.$$ $vg
+pvcreate -u $TEST_UUID --restorefile  backup.$$ "$dev5"
+vgremove -f $vg
+pvresize --setphysicalvolumesize 10M "$dev1"
+
+# test various errors and obsoleted tools
+not lvmchange
+not lvrename $vg
+not lvrename $vg-xxx
+not lvrename $vg  $vg/$lv-rename $vg/$lv
diff --git a/test/shell/discards-thin.sh b/test/shell/discards-thin.sh
new file mode 100644 (file)
index 0000000..84688b4
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+#
+# test support of thin discards
+#
+
+. lib/test
+
+#
+# Main
+#
+aux have_thin 1 1 0 || skip
+
+aux prepare_pvs 2 64
+
+vgcreate $vg -s 64K $(cat DEVICES)
+
+# Create named pool only
+lvcreate -l1 --discards ignore -T $vg/pool
+check lv_field $vg/pool discards "ignore"
+lvcreate -l1 --discards nopassdown -T $vg/pool1
+check lv_field $vg/pool1 discards "nopassdown"
+lvcreate -l1 --discards passdown -T $vg/pool2
+check lv_field $vg/pool2 discards "passdown"
+
+lvchange --discards nopassdown $vg/pool2
+
+# cannot convert active  ignore -> passdown
+not lvchange --discards passdown $vg/pool
+
+# cannot convert active  nopassdown -> ignore
+not lvchange --discards ignore $vg/pool1
+
+# deactivate
+lvchange -an $vg/pool $vg/pool1
+lvchange --discards passdown $vg/pool
+check lv_field $vg/pool discards "passdown"
+lvchange --discards ignore $vg/pool1
+check lv_field $vg/pool1 discards "ignore"
+
+vgremove -ff $vg
diff --git a/test/shell/dmeventd-restart.sh b/test/shell/dmeventd-restart.sh
new file mode 100644 (file)
index 0000000..fa9db46
--- /dev/null
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_dmeventd
+
+aux prepare_vg 5
+
+lvcreate -m 3 --ig -L 1 -n 4way $vg
+lvchange --monitor y $vg/4way
+lvcreate -m 2 --ig -L 1 -n 3way $vg
+lvchange --monitor y $vg/3way
+
+dmeventd -R -f &
+echo $! >LOCAL_DMEVENTD
+sleep 2 # wait a bit, so we talk to the new dmeventd later
+
+lvchange --monitor y --verbose $vg/3way 2>&1 | tee lvchange.out
+grep 'already monitored' lvchange.out
+lvchange --monitor y --verbose $vg/4way 2>&1 | tee lvchange.out
+grep 'already monitored' lvchange.out
+
+# now try what happens if no dmeventd is running
+kill -9 $(cat LOCAL_DMEVENTD)
+rm LOCAL_DMEVENTD
+
+dmeventd -R -f &
+echo $! >LOCAL_DMEVENTD
+
+# wait longer as tries to communicate with killed daemon
+sleep 7
+# now dmeventd should not be running
+not pgrep dmeventd
+rm LOCAL_DMEVENTD
+
+# set dmeventd path
+aux lvmconf "dmeventd/executable=\"$abs_top_builddir/test/lib/dmeventd\""
+lvchange --monitor y --verbose $vg/3way 2>&1 | tee lvchange.out
+pgrep dmeventd >LOCAL_DMEVENTD
+not grep 'already monitored' lvchange.out
+
+vgremove -ff $vg
diff --git a/test/shell/dumpconfig.sh b/test/shell/dumpconfig.sh
new file mode 100644 (file)
index 0000000..a16f753
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/sh
+# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+flatten() {
+       cat > flatten.config
+       for s in `egrep '^[a-z]+ {$' flatten.config | sed -e s,{$,,`; do
+               sed -e "/^$s/,/^}/p;d" flatten.config | sed -e '1d;$d' | sed -e "s,^[ \t]*,$s/,";
+       done
+}
+
+# clvmd might not be started fast enough and
+# lvm still activates locking for all commands.
+# FIXME: Either make longer start delay,
+#  or even better do not initialize
+#  locking for commands like 'dumpconfig'
+#aux lvmconf "global/locking_type=0"
+
+lvm dumpconfig -f lvmdumpconfig
+flatten < lvmdumpconfig | sort > config.dump
+flatten < etc/lvm.conf | sort > config.input
+# check that dumpconfig output corresponds to the lvm.conf input
+diff -wu config.input config.dump
+
+# and that merging multiple config files (through tags) works
+lvm dumpconfig -f lvmdumpconfig
+flatten < lvmdumpconfig | not grep 'log/verbose=1'
+lvm dumpconfig -f lvmdumpconfig
+flatten < lvmdumpconfig | grep 'log/indent=1'
+
+aux lvmconf 'tags/@foo {}'
+echo 'log { verbose = 1 }' > etc/lvm_foo.conf
+lvm dumpconfig -f lvmdumpconfig
+flatten < lvmdumpconfig | grep 'log/verbose=1'
+lvm dumpconfig -f lvmdumpconfig
+flatten < lvmdumpconfig | grep 'log/indent=1'
diff --git a/test/shell/fsadm.sh b/test/shell/fsadm.sh
new file mode 100644 (file)
index 0000000..4e624db
--- /dev/null
@@ -0,0 +1,160 @@
+#!/bin/sh
+# Copyright (C) 2008-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+test_description='Exercise fsadm filesystem resize'
+
+. lib/test
+
+aux prepare_vg 1 100
+
+# set to "skip" to avoid testing given fs and test warning result
+# i.e. check_reiserfs=skip
+check_ext3=
+check_xfs=
+check_reiserfs=
+
+which mkfs.ext3 || check_ext3=${check_ext3:-mkfs.ext3}
+which fsck.ext3 || check_ext3=${check_ext3:-fsck.ext3}
+which mkfs.xfs || check_xfs=${check_xfs:-mkfs.xfs}
+which xfs_check || check_xfs=${check_xfs:-xfs_check}
+which mkfs.reiserfs || check_reiserfs=${check_reiserfs:-mkfs.reiserfs}
+which reiserfsck || check_reiserfs=${check_reiserfs:-reiserfsck}
+
+vg_lv=$vg/$lv1
+vg_lv2=$vg/${lv1}bar
+dev_vg_lv="$DM_DEV_DIR/$vg_lv"
+dev_vg_lv2="$DM_DEV_DIR/$vg_lv2"
+mount_dir="mnt"
+mount_space_dir="mnt space dir"
+# for recursive call
+export LVM_BINARY=$(which lvm)
+
+test ! -d "$mount_dir" && mkdir "$mount_dir"
+test ! -d "$mount_space_dir" && mkdir "$mount_space_dir"
+
+cleanup_mounted_and_teardown()
+{
+       umount "$mount_dir" || true
+       umount "$mount_space_dir" || true
+       aux teardown
+}
+
+fscheck_ext3()
+{
+       fsck.ext3 -p -F -f "$dev_vg_lv"
+}
+
+fscheck_xfs()
+{
+       xfs_check "$dev_vg_lv"
+}
+
+fscheck_reiserfs()
+{
+       reiserfsck --check -p -f "$dev_vg_lv" </dev/null
+}
+
+check_missing()
+{
+       eval local t=$\check_$1
+       test -z "$t" && return 0
+       test "$t" = skip && return 1
+       # trick for warning test
+       echo "WARNING: fsadm test skipped $1 tests, $t tool is missing"
+       return 1
+}
+
+# Test for block sizes != 1024 (rhbz #480022)
+lvcreate -n $lv1 -L20M $vg
+lvcreate -n ${lv1}bar -L10M $vg
+trap 'cleanup_mounted_and_teardown' EXIT
+
+if check_missing ext2; then
+       mkfs.ext2 -b4096 -j "$dev_vg_lv"
+
+       fsadm --lvresize resize $vg_lv 30M
+       # Fails - not enough space for 4M fs
+       not fsadm -y --lvresize resize "$dev_vg_lv" 4M
+       lvresize -L+10M -r $vg_lv
+       lvreduce -L10M -r $vg_lv
+
+       fscheck_ext3
+       mount "$dev_vg_lv" "$mount_dir"
+       not fsadm -y --lvresize resize $vg_lv 4M
+       echo n | not lvresize -L4M -r -n $vg_lv
+       lvresize -L+20M -r -n $vg_lv
+       umount "$mount_dir"
+       fscheck_ext3
+
+       lvresize -f -L20M $vg_lv
+fi
+
+if check_missing ext3; then
+       mkfs.ext3 -b4096 -j "$dev_vg_lv"
+       mkfs.ext3 -b4096 -j "$dev_vg_lv2"
+
+       fsadm --lvresize resize $vg_lv 30M
+       # Fails - not enough space for 4M fs
+       not fsadm -y --lvresize resize "$dev_vg_lv" 4M
+       lvresize -L+10M -r $vg_lv
+       lvreduce -L10M -r $vg_lv
+
+       fscheck_ext3
+       mount "$dev_vg_lv" "$mount_dir"
+       lvresize -L+10M -r $vg_lv
+       mount "$dev_vg_lv2" "$mount_space_dir"
+       fsadm --lvresize -e -y resize $vg_lv2 25M
+
+       not fsadm -y --lvresize resize $vg_lv 4M
+       echo n | not lvresize -L4M -r -n $vg_lv
+       lvresize -L+20M -r -n $vg_lv
+       umount "$mount_dir"
+       umount "$mount_space_dir"
+       fscheck_ext3
+
+       lvresize -f -L20M $vg_lv
+fi
+
+if check_missing xfs; then
+       mkfs.xfs -l internal,size=1000b -f "$dev_vg_lv"
+
+       fsadm --lvresize resize $vg_lv 30M
+       # Fails - not enough space for 4M fs
+       lvresize -L+10M -r $vg_lv
+       not lvreduce -L10M -r $vg_lv
+
+       fscheck_xfs
+       mount "$dev_vg_lv" "$mount_dir"
+       lvresize -L+10M -r -n $vg_lv
+       umount "$mount_dir"
+       fscheck_xfs
+
+       lvresize -f -L20M $vg_lv
+fi
+
+if check_missing reiserfs; then
+       mkfs.reiserfs -s 513 -f "$dev_vg_lv"
+
+       fsadm --lvresize resize $vg_lv 30M
+       lvresize -L+10M -r $vg_lv
+       fsadm --lvresize -y resize $vg_lv 10M
+
+       fscheck_reiserfs
+       mount "$dev_vg_lv" "$mount_dir"
+
+       fsadm -y --lvresize resize $vg_lv 30M
+       umount "$mount_dir"
+       fscheck_reiserfs
+
+       lvresize -f -L20M $vg_lv
+fi
+
+vgremove -ff $vg
diff --git a/test/shell/inconsistent-metadata.sh b/test/shell/inconsistent-metadata.sh
new file mode 100644 (file)
index 0000000..9f4ffd2
--- /dev/null
@@ -0,0 +1,80 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_vg 3 12
+
+lvcreate -m 1 -l 1 -n mirror $vg
+lvcreate -l 1 -n resized $vg
+lvchange -a n $vg/mirror
+
+aux backup_dev $(cat DEVICES)
+
+init() {
+       aux restore_dev $(cat DEVICES)
+       lvs -o lv_name,lv_size --units k $vg | tee lvs.out
+       grep resized lvs.out | not grep 8192
+       lvresize -L 8192K $vg/resized
+       aux restore_dev "$dev1"
+}
+
+check() {
+       lvs -o lv_name,lv_size --units k $vg | tee lvs.out
+       grep resized lvs.out | grep 8192
+}
+
+# vgscan fixes up metadata (needs --cache option for direct scan if lvmetad is used)
+test -e LOCAL_LVMETAD && cache="--cache"
+init
+vgscan $cache 2>&1 | tee cmd.out
+grep "Inconsistent metadata found for VG $vg" cmd.out
+test -e LOCAL_LVMETAD && vgrename $vg foo && vgrename foo $vg # trigger a write
+vgscan $cache 2>&1 | tee cmd.out
+not grep "Inconsistent metadata found for VG $vg" cmd.out
+check
+
+# only vgscan would have noticed metadata inconsistencies when lvmetad is active
+if !test -e LOCAL_LVMETAD; then
+       # vgdisplay fixes
+       init
+       vgdisplay $vg 2>&1 | tee cmd.out
+       grep "Inconsistent metadata found for VG $vg" cmd.out
+       vgdisplay $vg 2>&1 | tee cmd.out
+       not grep "Inconsistent metadata found for VG $vg" cmd.out
+       check
+
+       # lvs fixes up
+       init
+       lvs $vg 2>&1 | tee cmd.out
+       grep "Inconsistent metadata found for VG $vg" cmd.out
+       vgdisplay $vg 2>&1 | tee cmd.out
+       not grep "Inconsistent metadata found for VG $vg" cmd.out
+       check
+
+       # vgs fixes up as well
+       init
+       vgs $vg 2>&1 | tee cmd.out
+       grep "Inconsistent metadata found for VG $vg" cmd.out
+       vgs $vg 2>&1 | tee cmd.out
+       not grep "Inconsistent metadata found for VG $vg" cmd.out
+       check
+fi
+
+echo Check auto-repair of failed vgextend - metadata written to original pv but not new pv
+vgremove -f $vg
+pvremove -ff $(cat DEVICES)
+pvcreate $(cat DEVICES)
+aux backup_dev "$dev2"
+vgcreate $vg "$dev1"
+vgextend $vg "$dev2"
+aux restore_dev "$dev2"
+should check compare_fields vgs $vg vg_mda_count pvs "$dev2" vg_mda_count
diff --git a/test/shell/listings.sh b/test/shell/listings.sh
new file mode 100644 (file)
index 0000000..b6e4dfa
--- /dev/null
@@ -0,0 +1,69 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+#
+# tests functionality of lvs, pvs, vgs, *display tools
+#
+
+. lib/test
+
+aux prepare_devs 5
+
+pvcreate "$dev1"
+pvcreate --metadatacopies 0 "$dev2"
+pvcreate --metadatacopies 0 "$dev3"
+pvcreate "$dev4"
+pvcreate --metadatacopies 0 "$dev5"
+
+#COMM bz195276 -- pvs doesn't show PVs until a VG is created
+test $(pvs --noheadings $(cat DEVICES) | wc -l) -eq 5
+
+#COMM pvs with segment attributes works even for orphans
+test $(pvs --noheadings -o seg_all,pv_all,lv_all,vg_all $(cat DEVICES) | wc -l) -eq 5
+
+vgcreate -c n $vg $(cat DEVICES)
+
+#COMM pvs and vgs report mda_count, mda_free (bz202886, bz247444)
+pvs -o +pv_mda_count,pv_mda_free $(cat DEVICES)
+for I in "$dev2" "$dev3" "$dev5"; do
+       check pv_field $I pv_mda_count 0
+       check pv_field $I pv_mda_free 0
+done
+vgs -o +vg_mda_count,vg_mda_free $vg
+check vg_field $vg vg_mda_count 2
+
+#COMM pvs doesn't display --metadatacopies 0 PVs as orphans (bz409061)
+pvdisplay "$dev2"|grep "VG Name.*$vg"
+check pv_field "$dev2" vg_name $vg
+
+#COMM lvs displays snapshots (bz171215)
+lvcreate -l4 -n $lv1 $vg
+lvcreate -l4 -s -n $lv2 $vg/$lv1
+test $(lvs --noheadings $vg | wc -l) -eq 2
+# should lvs -a display cow && real devices? (it doesn't)
+test $(lvs -a --noheadings $vg | wc -l)  -eq 2
+dmsetup ls|grep $PREFIX|grep -v "LVMTEST.*pv."
+lvremove -f $vg/$lv2
+
+#COMM lvs -a displays mirror legs and log
+lvcreate -l4 -m2 -n $lv3 $vg
+test $(lvs --noheadings $vg | wc -l) -eq 2
+test $(lvs -a --noheadings $vg | wc -l) -eq 6
+dmsetup ls|grep $PREFIX|grep -v "LVMTEST.*pv."
+
+#COMM vgs with options from pvs still treats arguments as VGs (bz193543)
+vgs -o pv_name,vg_name $vg
+# would complain if not
+
+#COMM pvdisplay --maps feature (bz149814)
+pvdisplay $(cat DEVICES) >out
+pvdisplay --maps $(cat DEVICES) >out2
+not diff out out2
diff --git a/test/shell/lock-blocking.sh b/test/shell/lock-blocking.sh
new file mode 100644 (file)
index 0000000..480a73b
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+test_description='test some blocking / non-blocking multi-vg operations'
+
+. lib/test
+
+aux prepare_devs 3
+test -e LOCAL_CLVMD && skip
+pvcreate "$dev1" "$dev2"
+vgcreate $vg "$dev1" "$dev2"
+
+# if wait_for_locks set, vgremove should wait for orphan lock
+# flock process should have exited by the time first vgremove completes
+flock -w 5 $TESTDIR/var/lock/lvm/P_orphans -c "sleep 10" &
+while ! test -f $TESTDIR/var/lock/lvm/P_orphans ; do sleep .1 ; done
+
+vgremove --config 'global { wait_for_locks = 1 }' $vg
+not vgremove --config 'global { wait_for_locks = 1 }' $vg
+
+test ! -f $TESTDIR/var/lock/lvm/P_orphans
+
+# if wait_for_locks not set, vgremove should fail on non-blocking lock
+# we must wait for flock process at the end - vgremove won't wait
+vgcreate $vg "$dev1" "$dev2"
+flock -w 5 $TESTDIR/var/lock/lvm/P_orphans -c "sleep 10" &
+
+while ! test -f $TESTDIR/var/lock/lvm/P_orphans ; do sleep .1 ; done
+flock_pid=`jobs -p`
+
+not vgremove --config 'global { wait_for_locks = 0 }' $vg
+test -f $TESTDIR/var/lock/lvm/P_orphans # still running
+kill $flock_pid
diff --git a/test/shell/lvchange-mirror.sh b/test/shell/lvchange-mirror.sh
new file mode 100644 (file)
index 0000000..26656d4
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_dmeventd
+aux prepare_vg 3
+
+# force resync 2-way active mirror
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0-1
+check mirror $vg $lv1 "$dev3"
+echo y | lvchange --resync $vg/$lv1
+check mirror $vg $lv1 "$dev3"
+lvremove -ff $vg
+
+# force resync 2-way inactive mirror
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0-1
+lvchange -an $vg/$lv1
+check mirror $vg $lv1 "$dev3"
+lvchange --resync $vg/$lv1
+check mirror $vg $lv1 "$dev3"
+lvremove -ff $vg
diff --git a/test/shell/lvchange-partial.sh b/test/shell/lvchange-partial.sh
new file mode 100644 (file)
index 0000000..fe642d4
--- /dev/null
@@ -0,0 +1,66 @@
+#!/bin/bash
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux target_at_least dm-raid 1 1 0 || skip
+
+aux prepare_vg 2
+
+lvcreate --type raid1 -m 1 -l 2 -n $lv1 $vg
+lvchange -an $vg/$lv1
+aux disable_dev "$dev1"
+
+#
+# Test for allowable metadata changes
+#
+# contiguous_ARG
+lvchange -C y $vg/$lv1
+lvchange -C n $vg/$lv1
+
+# permission_ARG
+lvchange -p r $vg/$lv1
+lvchange -p rw $vg/$lv1
+
+# readahead_ARG
+lvchange -r none $vg/$lv1
+lvchange -r auto $vg/$lv1
+
+# persistent_ARG
+lvchange -M y --minor 56 --major 253 $vg/$lv1
+lvchange -M n $vg/$lv1
+
+# addtag_ARG
+# deltag_ARG
+lvchange --addtag foo $vg/$lv1
+lvchange --deltag foo $vg/$lv1
+
+#
+# Test for disallowed metadata changes
+#
+# resync_ARG
+not lvchange --resync $vg/$lv1
+
+# alloc_ARG
+not lvchange --alloc anywhere $vg/$lv1
+
+# discards_ARG
+not lvchange --discards ignore $vg/$lv1
+
+# zero_ARG
+not lvchange --zero y $vg/$lv1
+
+#
+# Ensure that allowed args don't cause disallowed args to get through
+#
+not lvchange --resync -ay $vg/$lv1
+not lvchange --resync --addtag foo $vg/$lv1
+
diff --git a/test/shell/lvconvert-mirror-basic-0.sh b/test/shell/lvconvert-mirror-basic-0.sh
new file mode 100644 (file)
index 0000000..dc71bb8
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. ./shell/lvconvert-mirror-basic.sh
+test_many 0
diff --git a/test/shell/lvconvert-mirror-basic-1.sh b/test/shell/lvconvert-mirror-basic-1.sh
new file mode 100644 (file)
index 0000000..b7ebf9e
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. ./shell/lvconvert-mirror-basic.sh
+test_many 1
diff --git a/test/shell/lvconvert-mirror-basic-2.sh b/test/shell/lvconvert-mirror-basic-2.sh
new file mode 100644 (file)
index 0000000..d47f77d
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. ./shell/lvconvert-mirror-basic.sh
+test_many 2
diff --git a/test/shell/lvconvert-mirror-basic-3.sh b/test/shell/lvconvert-mirror-basic-3.sh
new file mode 100644 (file)
index 0000000..732fb2d
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. ./shell/lvconvert-mirror-basic.sh
+test_many 3
diff --git a/test/shell/lvconvert-mirror-basic.sh b/test/shell/lvconvert-mirror-basic.sh
new file mode 100644 (file)
index 0000000..a0f50f6
--- /dev/null
@@ -0,0 +1,132 @@
+#!/bin/sh
+# Copyright (C) 2010-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+log_name_to_count() {
+       case "$1"  in
+       mirrored) echo 2 ;;
+       disk)     echo 1 ;;
+       *)        echo 0 ;;
+       esac
+}
+
+# FIXME: For test_[up|down]convert, I'd still like to be able
+# to specifiy devices - especially if I can do partial PV
+# specification for down-converts.  It may even be wise to
+# do one round through these tests without specifying the PVs
+# to use and one round where we do.
+
+# test_lvconvert
+#   start_mirror_count:  The '-m' argument to create with
+#   start_log_type: core|disk|mirrored
+#   final_mirror_count: The '-m' argument to convert to
+#   final_log_type: core|disk|mirrored
+#   active: Whether the LV should be active when the convert happens
+#
+# Exmaple: Convert 3-way disk-log mirror to
+#          2-way disk-log mirror while not active
+# -> test_lvconvert 2 disk 3 disk 0
+
+test_lvconvert() {
+       local start_count=$1
+       local start_count_p1=$(($start_count + 1))
+       local start_log_type=$2
+       local finish_count=$3
+       local finish_count_p1=$(($finish_count + 1))
+       local finish_log_type=$4
+       local dev_array=("$dev1" "$dev2" "$dev3" "$dev4" "$dev5")
+       local start_log_count
+       local finish_log_count
+       local max_log_count
+       local alloc=""
+       local active=true
+       local i
+
+       test "$5" = "active" && active=false
+       #test $finish_count -gt $start_count && up=true
+
+       # Do we have enough devices for the mirror images?
+       test $start_count_p1 -gt ${#dev_array[@]} && \
+               die "Action requires too many devices"
+
+       # Do we have enough devices for the mirror images?
+       test $finish_count_p1 -gt ${#dev_array[@]} && \
+               die "Action requires too many devices"
+
+       start_log_count=$(log_name_to_count $start_log_type)
+       finish_log_count=$(log_name_to_count $finish_log_type)
+       if [ $finish_log_count -gt $start_log_count ]; then
+               max_log_count=$finish_log_count
+       else
+               max_log_count=$start_log_count
+       fi
+
+       if [ $start_count -gt 0 ]; then
+               # Are there extra devices for the log or do we overlap
+               if [ $(($start_count_p1 + $start_log_count)) -gt ${#dev_array[@]} ]; then
+                       alloc="--alloc anywhere"
+               fi
+
+               lvcreate -l2 -m $start_count --mirrorlog $start_log_type \
+                       -n $lv1 $vg $alloc
+               check mirror_legs $vg $lv1 $start_count_p1
+               # FIXME: check mirror log
+       else
+               lvcreate -l2 -n $lv1 $vg
+       fi
+
+       lvs -a -o name,copy_percent,devices $vg
+       test $active || lvchange -an $vg/$lv1
+
+       # Are there extra devices for the log or do we overlap
+       if [ $(($finish_count_p1 + $finish_log_count)) -gt ${#dev_array[@]} ]; then
+               alloc="--alloc anywhere"
+       fi
+
+       lvconvert -m $finish_count --mirrorlog $finish_log_type \
+               $vg/$lv1 $alloc
+
+       test $active || lvchange -ay $vg/$lv1
+
+       check mirror_no_temporaries $vg $lv1
+       if [ "$finish_count_p1" -eq 1 ]; then
+               check linear $vg $lv1
+       else
+               if test -n "$alloc"; then
+                       check mirror_nonredundant $vg $lv1
+               else
+                       check mirror $vg $lv1
+               fi
+               check mirror_legs $vg $lv1 $finish_count_p1
+       fi
+}
+
+aux prepare_pvs 5 5
+vgcreate -c n -s 128k $vg $(cat DEVICES)
+
+test_many() {
+       i=$1
+       for j in $(seq 0 3); do
+               for k in core disk mirrored; do
+                       for l in core disk mirrored; do
+                               if test "$i" -eq "$j" && test "$k" = "$l"; then continue; fi
+                               : ----------------------------------------------------
+                               : "Testing mirror conversion -m$i/$k -> -m$j/$l"
+                               : ----------------------------------------------------
+                               test_lvconvert $i $k $j $l 0
+                               lvremove -ff $vg
+                               test_lvconvert $i $k $j $l 1
+                               lvremove -ff $vg
+                       done
+               done
+       done
+}
diff --git a/test/shell/lvconvert-mirror.sh b/test/shell/lvconvert-mirror.sh
new file mode 100644 (file)
index 0000000..c09b8fd
--- /dev/null
@@ -0,0 +1,280 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_pvs 5 10
+# FIXME - test fails with extent size < 512k
+vgcreate -c n -s 512k $vg $(cat DEVICES)
+
+# convert from linear to 2-way mirror
+lvcreate -l2 -n $lv1 $vg "$dev1"
+lvconvert -i1 -m+1 $vg/$lv1 "$dev2" "$dev3:0-1"
+check mirror $vg $lv1 "$dev3"
+lvremove -ff $vg
+
+# convert from linear to 2-way mirror - with tags and volume_list (bz683270)
+lvcreate -l2 -n $lv1 $vg --addtag hello
+lvconvert -i1 -m+1 $vg/$lv1 \
+    --config 'activation { volume_list = [ "@hello" ] }'
+lvremove -ff $vg
+
+# convert from 2-way to 3-way mirror - with tags and volume_list (bz683270)
+lvcreate -l2 -m1 -n $lv1 $vg --addtag hello
+lvconvert -i1 -m+1 $vg/$lv1 \
+    --config 'activation { volume_list = [ "@hello" ] }'
+lvremove -ff $vg
+
+# convert from 2-way mirror to linear
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0-1"
+lvconvert -m-1 $vg/$lv1
+check linear $vg $lv1
+lvremove -ff $vg
+# and now try removing a specific leg (bz453643)
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0-1"
+lvconvert -m0 $vg/$lv1 "$dev2"
+check lv_on $vg $lv1 "$dev1"
+lvremove -ff $vg
+
+# convert from disklog to corelog, active
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0-1"
+lvconvert -f --mirrorlog core $vg/$lv1
+check mirror $vg $lv1 core
+lvremove -ff $vg
+
+# convert from corelog to disklog, active
+lvcreate -l2 -m1 --mirrorlog core -n $lv1 $vg "$dev1" "$dev2"
+lvconvert --mirrorlog disk $vg/$lv1 "$dev3:0-1"
+check mirror $vg $lv1 "$dev3"
+lvremove -ff $vg
+
+# bz192865: lvconvert log of an inactive mirror lv
+# convert from disklog to corelog, inactive
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0-1"
+lvchange -an $vg/$lv1
+echo y | lvconvert -f --mirrorlog core $vg/$lv1
+check mirror $vg $lv1 core
+lvremove -ff $vg
+
+# convert from corelog to disklog, inactive
+lvcreate -l2 -m1 --mirrorlog core -n $lv1 $vg "$dev1" "$dev2"
+lvchange -an $vg/$lv1
+lvconvert --mirrorlog disk $vg/$lv1 "$dev3:0-1"
+check mirror $vg $lv1 "$dev3"
+lvremove -ff $vg
+
+# convert linear to 2-way mirror with 1 PV
+lvcreate -l2 -n $lv1 $vg "$dev1"
+not lvconvert -m+1 --mirrorlog core $vg/$lv1 "$dev1"
+lvremove -ff $vg
+
+# Start w/ 3-way mirror
+# Test pulling primary image before mirror in-sync (should fail)
+# Test pulling primary image after mirror in-sync (should work)
+# Test that the correct devices remain in the mirror
+lvcreate -l2 -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev4" "$dev3:0"
+# FIXME:
+#  This is somewhat timing dependent - sync /could/ finish before
+#  we get a chance to have this command fail
+should not lvconvert -m-1 $vg/$lv1 "$dev1"
+
+lvconvert $vg/$lv1 # wait
+lvconvert -m2 $vg/$lv1 "$dev1" "$dev2" "$dev4" "$dev3:0" # If the above "should" failed...
+
+aux wait_for_sync $vg $lv1
+lvconvert -m-1 $vg/$lv1 "$dev1"
+check mirror_images_on $lv1 "$dev2" "$dev4"
+lvconvert -m-1 $vg/$lv1 "$dev2"
+check linear $vg $lv1
+check lv_on $vg $lv1 "$dev4"
+lvremove -ff $vg
+
+# No parallel lvconverts on a single LV please
+
+lvcreate -l5 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0"
+check mirror $vg $lv1
+check mirror_legs $vg $lv1 2
+lvconvert -m+1 -b $vg/$lv1 "$dev4"
+
+# Next convert should fail b/c we can't have 2 at once
+should not lvconvert -m+1 $vg/$lv1 "$dev5"
+lvconvert $vg/$lv1 # wait
+lvconvert -m2 $vg/$lv1 # In case the above "should" actually failed
+
+check mirror $vg $lv1 "$dev3"
+check mirror_no_temporaries $vg $lv1
+check mirror_legs $vg $lv1 3
+lvremove -ff $vg
+
+# add 1 mirror to core log mirror, but
+#  implicitly keep log as 'core'
+lvcreate -l2 -m1 --mirrorlog core -n $lv1 $vg "$dev1" "$dev2"
+lvconvert -m +1 -i1 $vg/$lv1
+
+check mirror $vg $lv1 core
+check mirror_no_temporaries $vg $lv1
+check mirror_legs $vg $lv1 3
+lvremove -ff $vg
+
+# remove 1 mirror from corelog'ed mirror; should retain 'core' log type
+lvcreate -l2 -m2 --corelog -n $lv1 $vg
+lvconvert -m -1 -i1 $vg/$lv1
+
+check mirror $vg $lv1 core
+check mirror_no_temporaries $vg $lv1
+check mirror_legs $vg $lv1 2
+lvremove -ff $vg
+
+# add 1 mirror then add 1 more mirror during conversion
+# FIXME this has been explicitly forbidden?
+#lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0
+#lvconvert -m+1 -b $vg/$lv1 "$dev4"
+#lvconvert -m+1 $vg/$lv1 "$dev5"
+#
+#check mirror $vg $lv1 "$dev3"
+#check mirror_no_temporaries $vg $lv1
+#check mirror_legs $vg $lv1 4
+#lvremove -ff $vg
+
+# Linear to mirror with mirrored log using --alloc anywhere
+lvcreate -l2 -n $lv1 $vg "$dev1"
+lvconvert -m +1 --mirrorlog mirrored --alloc anywhere $vg/$lv1 "$dev1" "$dev2"
+should check mirror $vg $lv1
+lvremove -ff $vg
+
+# convert inactive mirror and start polling
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0"
+lvchange -an $vg/$lv1
+lvconvert -m+1 $vg/$lv1 "$dev4"
+lvchange -ay $vg/$lv1
+lvconvert $vg/$lv1 # wait
+check mirror $vg $lv1 "$dev3"
+check mirror_no_temporaries $vg $lv1
+lvremove -ff $vg
+
+# ---------------------------------------------------------------------
+# removal during conversion
+
+# "remove newly added mirror"
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0"
+lvconvert -m+1 -b $vg/$lv1 "$dev4"
+lvconvert -m-1 $vg/$lv1 "$dev4"
+lvconvert $vg/$lv1 # wait
+
+check mirror $vg $lv1 "$dev3"
+check mirror_no_temporaries $vg $lv1
+check mirror_legs $vg $lv1 2
+lvremove -ff $vg
+
+# "remove one of newly added mirrors"
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0"
+lvconvert -m+2 -b $vg/$lv1 "$dev4" "$dev5"
+lvconvert -m-1 $vg/$lv1 "$dev4"
+lvconvert $vg/$lv1 # wait
+
+check mirror $vg $lv1 "$dev3"
+check mirror_no_temporaries $vg $lv1
+check mirror_legs $vg $lv1 3
+lvremove -ff $vg
+
+# "remove from original mirror (the original is still mirror)"
+lvcreate -l2 -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev5" "$dev3:0"
+lvconvert -m+1 -b $vg/$lv1 "$dev4"
+lvconvert -m-1 $vg/$lv1 "$dev2"
+lvconvert $vg/$lv1
+
+check mirror $vg $lv1 "$dev3"
+check mirror_no_temporaries $vg $lv1
+check mirror_legs $vg $lv1 3
+lvremove -ff $vg
+
+# "remove from original mirror (the original becomes linear)"
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0"
+lvconvert -m+1 -b $vg/$lv1 "$dev4"
+lvconvert -m-1 $vg/$lv1 "$dev2"
+lvconvert $vg/$lv1
+
+check mirror $vg $lv1 "$dev3"
+check mirror_no_temporaries $vg $lv1
+check mirror_legs $vg $lv1 2
+lvremove -ff $vg
+
+# ---------------------------------------------------------------------
+
+# "rhbz440405: lvconvert -m0 incorrectly fails if all PEs allocated"
+lvcreate -l`pvs --noheadings -ope_count "$dev1"` -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0"
+aux wait_for_sync $vg $lv1
+lvconvert -m0 $vg/$lv1 "$dev1"
+check linear $vg $lv1
+lvremove -ff $vg
+
+# "rhbz264241: lvm mirror doesn't lose it's "M" --nosync attribute after being down and the up converted"
+lvcreate -l2 -m1 -n$lv1 --nosync $vg
+lvconvert -m0 $vg/$lv1
+lvconvert -m1 $vg/$lv1
+lvs --noheadings -o attr $vg/$lv1 | grep '^ *m'
+lvremove -ff $vg
+
+# lvconvert from linear (on multiple PVs) to mirror
+lvcreate -l 8 -n $lv1 $vg "$dev1:0-3" "$dev2:0-3"
+lvconvert -m1 $vg/$lv1
+
+should check mirror $vg $lv1
+check mirror_legs $vg $lv1 2
+lvremove -ff $vg
+
+# BZ 463272: disk log mirror convert option is lost if downconvert option is also given
+lvcreate -l1 -m2 --corelog -n $lv1 $vg "$dev1" "$dev2" "$dev3"
+aux wait_for_sync $vg $lv1
+lvconvert -m1 --mirrorlog disk $vg/$lv1
+check mirror $vg $lv1
+not check mirror $vg $lv1 core
+lvremove -ff $vg
+
+# ---
+# add mirror and disk log
+
+# "add 1 mirror and disk log"
+lvcreate -l2 -m1 --mirrorlog core -n $lv1 $vg "$dev1" "$dev2"
+
+# FIXME on next line, specifying $dev3:0 $dev4 (i.e log device first) fails (!)
+lvconvert -m+1 --mirrorlog disk -i1 $vg/$lv1 "$dev4" "$dev3:0"
+
+check mirror $vg $lv1 "$dev3"
+check mirror_no_temporaries $vg $lv1
+check mirror_legs $vg $lv1 3
+lvremove -ff $vg
+
+# simple mirrored stripe
+lvcreate -i2 -l10 -n $lv1 $vg
+lvconvert -m1 -i1 $vg/$lv1
+lvreduce -f -l1 $vg/$lv1
+lvextend -f -l10 $vg/$lv1
+lvremove -ff $vg/$lv1
+
+# extents must be divisible
+lvcreate -l15 -n $lv1 $vg
+not lvconvert -m1 --corelog --stripes 2 $vg/$lv1
+lvremove -ff $vg
+
+# Should not be able to add images to --nosync mirror
+# but should be able to after 'lvchange --resync'
+lvcreate -m 1 -l1 -n $lv1 $vg --nosync
+not lvconvert -m +1 $vg/$lv1
+lvchange --resync -y $vg/$lv1
+lvconvert -m +1 $vg/$lv1
+lvremove -ff $vg
+
+lvcreate -m 1 --corelog -l1 -n $lv1 $vg --nosync
+not lvconvert -m +1 $vg/$lv1
+lvchange --resync -y $vg/$lv1
+lvconvert -m +1 $vg/$lv1
+lvremove -ff $vg
diff --git a/test/shell/lvconvert-raid.sh b/test/shell/lvconvert-raid.sh
new file mode 100644 (file)
index 0000000..4fa766d
--- /dev/null
@@ -0,0 +1,223 @@
+#!/bin/sh
+# Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+get_image_pvs() {
+       local d
+       local images
+
+       images=`dmsetup ls | grep ${1}-${2}_.image_.* | cut -f1 | sed -e s:-:/:`
+       lvs --noheadings -a -o devices $images | sed s/\(.\)//
+}
+
+########################################################
+# MAIN
+########################################################
+aux target_at_least dm-raid 1 1 0 || skip
+aux kernel_at_least 3 2 0 || skip
+
+# 9 PVs needed for RAID10 testing (3-stripes/2-mirror - replacing 3 devs)
+aux prepare_pvs 9 80
+vgcreate -c n -s 256k $vg $(cat DEVICES)
+
+###########################################
+# RAID1 convert tests
+###########################################
+for under_snap in false true; do
+for i in 1 2 3 4; do
+       for j in 1 2 3 4; do
+               if [ $i -eq 1 ]; then
+                       from="linear"
+               else
+                       from="$i-way"
+               fi
+               if [ $j -eq 1 ]; then
+                       to="linear"
+               else
+                       to="$j-way"
+               fi
+
+               echo -n "Converting from $from to $to"
+               if $under_snap; then
+                       echo -n " (while under a snapshot)"
+               fi
+               echo
+
+               if [ $i -eq 1 ]; then
+                       # Shouldn't be able to create with just 1 image
+                       not lvcreate --type raid1 -m 0 -l 2 -n $lv1 $vg
+
+                       lvcreate -l 2 -n $lv1 $vg
+               else
+                       lvcreate --type raid1 -m $(($i - 1)) -l 2 -n $lv1 $vg
+                       aux wait_for_sync $vg $lv1
+               fi
+
+               if $under_snap; then
+                       lvcreate -s $vg/$lv1 -n snap -l 2
+               fi
+
+               lvconvert -m $((j - 1))  $vg/$lv1
+
+               # FIXME: ensure no residual devices
+
+               if [ $j -eq 1 ]; then
+                       check linear $vg $lv1
+               fi
+               lvremove -ff $vg
+       done
+done
+done
+
+##############################################
+# RAID1 - shouldn't be able to add image
+#         if created '--nosync', but should
+#         be able to after 'lvchange --resync'
+##############################################
+lvcreate --type raid1 -m 1 -l 2 -n $lv1 $vg --nosync
+not lvconvert -m +1 $vg/$lv1
+lvchange --resync -y $vg/$lv1
+aux wait_for_sync $vg $lv1
+lvconvert -m +1 $vg/$lv1
+lvremove -ff $vg
+
+# 3-way to 2-way convert while specifying devices
+lvcreate --type raid1 -m 2 -l 2 -n $lv1 $vg $dev1 $dev2 $dev3
+aux wait_for_sync $vg $lv1
+lvconvert -m1 $vg/$lv1 $dev2
+lvremove -ff $vg
+
+#
+# FIXME: Add tests that specify particular devices to be removed
+#
+
+###########################################
+# RAID1 split tests
+###########################################
+# 3-way to 2-way/linear
+lvcreate --type raid1 -m 2 -l 2 -n $lv1 $vg
+aux wait_for_sync $vg $lv1
+lvconvert --splitmirrors 1 -n $lv2 $vg/$lv1
+check lv_exists $vg $lv1
+check linear $vg $lv2
+# FIXME: ensure no residual devices
+lvremove -ff $vg
+
+# 2-way to linear/linear
+lvcreate --type raid1 -m 1 -l 2 -n $lv1 $vg
+aux wait_for_sync $vg $lv1
+lvconvert --splitmirrors 1 -n $lv2 $vg/$lv1
+check linear $vg $lv1
+check linear $vg $lv2
+# FIXME: ensure no residual devices
+lvremove -ff $vg
+
+# 3-way to linear/2-way
+lvcreate --type raid1 -m 2 -l 2 -n $lv1 $vg
+aux wait_for_sync $vg $lv1
+# FIXME: Can't split off a RAID1 from a RAID1 yet
+# 'should' results in "warnings"
+should lvconvert --splitmirrors 2 -n $lv2 $vg/$lv1
+#check linear $vg $lv1
+#check lv_exists $vg $lv2
+# FIXME: ensure no residual devices
+lvremove -ff $vg
+
+###########################################
+# RAID1 split + trackchanges / merge
+###########################################
+# 3-way to 2-way/linear
+lvcreate --type raid1 -m 2 -l 2 -n $lv1 $vg
+aux wait_for_sync $vg $lv1
+lvconvert --splitmirrors 1 --trackchanges $vg/$lv1
+check lv_exists $vg $lv1
+check linear $vg ${lv1}_rimage_2
+lvconvert --merge $vg/${lv1}_rimage_2
+# FIXME: ensure no residual devices
+lvremove -ff $vg
+
+###########################################
+# Mirror to RAID1 conversion
+###########################################
+for i in 1 2 3 ; do
+       lvcreate --type mirror -m $i -l 2 -n $lv1 $vg
+       aux wait_for_sync $vg $lv1
+       lvconvert --type raid1 $vg/$lv1
+       lvremove -ff $vg
+done
+
+###########################################
+# Device Replacement Testing
+###########################################
+# RAID1: Replace up to n-1 devices - trying different combinations
+# Test for 2-way to 4-way RAID1 LVs
+for i in {1..3}; do
+       lvcreate --type raid1 -m $i -l 2 -n $lv1 $vg
+
+       for j in $(seq $(($i + 1))); do # The number of devs to replace at once
+       for o in $(seq 0 $i); do        # The offset into the device list
+               replace=""
+
+               devices=( $(get_image_pvs $vg $lv1) )
+
+               for k in $(seq $j); do
+                       index=$((($k + $o) % ($i + 1)))
+                       replace="$replace --replace ${devices[$index]}"
+               done
+               aux wait_for_sync $vg $lv1
+
+               if [ $j -ge $((i + 1)) ]; then
+                       # Can't replace all at once.
+                       not lvconvert $replace $vg/$lv1
+               else
+                       lvconvert $replace $vg/$lv1
+               fi
+       done
+       done
+
+       lvremove -ff $vg
+done
+
+# RAID 4/5/6 (can replace up to 'parity' devices)
+for i in 4 5 6; do
+       lvcreate --type raid$i -i 3 -l 3 -n $lv1 $vg
+
+       if [ $i -eq 6 ]; then
+               dev_cnt=5
+               limit=2
+       else
+               dev_cnt=4
+               limit=1
+       fi
+
+       for j in {1..3}; do
+       for o in $(seq 0 $i); do
+               replace=""
+
+               devices=( $(get_image_pvs $vg $lv1) )
+
+               for k in $(seq $j); do
+                       index=$((($k + $o) % $dev_cnt))
+                       replace="$replace --replace ${devices[$index]}"
+               done
+               aux wait_for_sync $vg $lv1
+
+               if [ $j -gt $limit ]; then
+                       not lvconvert $replace $vg/$lv1
+               else
+                       lvconvert $replace $vg/$lv1
+               fi
+       done
+       done
+
+       lvremove -ff $vg
+done
diff --git a/test/shell/lvconvert-raid10.sh b/test/shell/lvconvert-raid10.sh
new file mode 100644 (file)
index 0000000..2e4381d
--- /dev/null
@@ -0,0 +1,56 @@
+#!/bin/sh
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+get_image_pvs() {
+       local d
+       local images
+
+       images=`dmsetup ls | grep ${1}-${2}_.image_.* | cut -f1 | sed -e s:-:/:`
+       lvs --noheadings -a -o devices $images | sed s/\(.\)//
+}
+
+########################################################
+# MAIN
+########################################################
+# RAID10: Can replace 'copies - 1' devices from each stripe
+# Tests are run on 2-way mirror, 3-way stripe RAID10
+aux target_at_least dm-raid 1 3 1 || skip
+
+# 9 PVs needed for RAID10 testing (3-stripes/2-mirror - replacing 3 devs)
+aux prepare_pvs 9 80
+vgcreate -c n -s 256k $vg $(cat DEVICES)
+
+lvcreate --type raid10 -m 1 -i 3 -l 3 -n $lv1 $vg
+aux wait_for_sync $vg $lv1
+
+# Can replace any single device
+for i in $(get_image_pvs $vg $lv1); do
+       lvconvert --replace $i $vg/$lv1
+       aux wait_for_sync $vg $lv1
+done
+
+# Can't replace adjacent devices
+devices=( $(get_image_pvs $vg $lv1) )
+not lvconvert --replace ${devices[0]} --replace ${devices[1]} $vg/$lv1
+not lvconvert --replace ${devices[2]} --replace ${devices[3]} $vg/$lv1
+not lvconvert --replace ${devices[4]} --replace ${devices[5]} $vg/$lv1
+
+# Can replace non-adjacent devices
+for i in 0 1; do
+       lvconvert \
+               --replace ${devices[$i]} \
+               --replace ${devices[$(($i + 2))]} \
+               --replace ${devices[$(($i + 4))]} \
+                $vg/$lv1
+       aux wait_for_sync $vg $lv1
+done
diff --git a/test/shell/lvconvert-repair-dmeventd.sh b/test/shell/lvconvert-repair-dmeventd.sh
new file mode 100644 (file)
index 0000000..66e4cc8
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+which mkfs.ext2 || skip
+
+aux prepare_vg 5
+aux prepare_dmeventd
+
+lvcreate -m 3 --ig -L 1 -n 4way $vg
+lvchange --monitor y $vg/4way
+aux disable_dev "$dev2" "$dev4"
+mkfs.ext2 $DM_DEV_DIR/$vg/4way
+sleep 10 # FIXME: need a "poll" utility, akin to "check"
+aux enable_dev "$dev2" "$dev4"
+check mirror $vg 4way
+check mirror_legs $vg 4way 2
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-repair-policy.sh b/test/shell/lvconvert-repair-policy.sh
new file mode 100644 (file)
index 0000000..e595d34
--- /dev/null
@@ -0,0 +1,91 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_vg 4
+aux lvmconf 'allocation/maximise_cling = 0'
+aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1'
+
+# Clean-up and create a 2-way mirror, where the the
+# leg devices are always on $dev[12] and the log
+# is always on $dev3.  ($dev4 behaves as a spare)
+cleanup() {
+       vgreduce --removemissing $vg
+       for d in "$@"; do aux enable_dev "$d"; done
+       for d in "$@"; do vgextend $vg "$d"; done
+       lvremove -ff $vg/mirror
+       lvcreate -m 1 --ig -l 2 -n mirror $vg "$dev1" "$dev2" "$dev3":0
+}
+
+repair() {
+       lvconvert --repair --use-policies --config "$1" $vg/mirror
+}
+
+lvcreate -m 1 -L 1 -n mirror $vg
+lvchange -a n $vg/mirror
+
+# Fail a leg of a mirror.
+aux disable_dev "$dev1"
+lvchange --partial -a y $vg/mirror
+repair 'activation { mirror_image_fault_policy = "remove" }'
+check linear $vg mirror
+cleanup "$dev1"
+
+# Fail a leg of a mirror.
+# Expected result: Mirror (leg replaced, should retain log)
+aux disable_dev "$dev1"
+repair 'activation { mirror_image_fault_policy = "replace" mirror_log_fault_policy = "remove" }'
+check mirror $vg mirror
+check active $vg mirror_mlog
+cleanup "$dev1"
+
+# Fail a leg of a mirror.
+# Expected result: Mirror (leg replaced)
+aux disable_dev "$dev1"
+repair 'activation { mirror_image_fault_policy = "replace" }'
+check mirror $vg mirror
+check active $vg mirror_mlog
+cleanup "$dev1"
+
+# Fail a leg of a mirror (use old name for policy specification)
+# Expected result: Mirror (leg replaced)
+aux disable_dev "$dev1"
+repair 'activation { mirror_image_fault_policy = "replace" }'
+check mirror $vg mirror
+check active $vg mirror_mlog
+cleanup "$dev1"
+
+# Fail a leg of a mirror w/ no available spare
+# Expected result: linear
+#                  (or 2-way with leg/log overlap if alloc anywhere)
+aux disable_dev "$dev2" "$dev4"
+repair 'activation { mirror_image_fault_policy = "replace" }'
+check mirror $vg mirror
+not check lv_exists $vg mirror_mlog
+cleanup "$dev2" "$dev4"
+
+# Fail the log device of a mirror w/ no available spare
+# Expected result: mirror w/ corelog
+aux disable_dev "$dev3" "$dev4"
+repair 'activation { mirror_image_fault_policy = "replace" }' $vg/mirror
+check mirror $vg mirror
+not check lv_exists $vg mirror_mlog
+cleanup "$dev3" "$dev4"
+
+# Fail the log device with a remove policy
+# Expected result: mirror w/ corelog
+lvchange -a y $vg/mirror
+aux disable_dev "$dev3" "$dev4"
+repair 'activation { mirror_log_fault_policy = "remove" }'
+check mirror $vg mirror core
+not check lv_exists $vg mirror_mlog
+cleanup "$dev3" "$dev4"
diff --git a/test/shell/lvconvert-repair-replace.sh b/test/shell/lvconvert-repair-replace.sh
new file mode 100644 (file)
index 0000000..974628a
--- /dev/null
@@ -0,0 +1,92 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_vg 6
+aux lvmconf 'allocation/maximise_cling = 0'
+aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1'
+
+# 3-way, disk log
+# multiple failures, full replace
+lvcreate --mirrorlog disk -m 2 --ig -L 1 -n 3way $vg "$dev1" "$dev2" "$dev3" "$dev4":0-1
+aux disable_dev "$dev1" "$dev2"
+echo y | lvconvert --repair $vg/3way 2>&1 | tee 3way.out
+lvs -a -o +devices $vg | not grep unknown
+not grep "WARNING: Failed" 3way.out
+vgreduce --removemissing $vg
+check mirror $vg 3way
+aux enable_dev "$dev1" "$dev2"
+
+vgremove -ff $vg; vgcreate -c n $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6"
+
+# 2-way, mirrored log
+# Double log failure, full replace
+lvcreate --mirrorlog mirrored -m 1 --ig -L 1 -n 2way $vg \
+    "$dev1" "$dev2" "$dev3":0 "$dev4":0
+aux disable_dev "$dev3" "$dev4"
+echo y | lvconvert --repair $vg/2way 2>&1 | tee 2way.out
+lvs -a -o +devices $vg | not grep unknown
+not grep "WARNING: Failed" 2way.out
+vgreduce --removemissing $vg
+check mirror $vg 2way
+aux enable_dev "$dev3" "$dev4"
+
+vgremove -ff $vg; vgcreate -c n $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6"
+
+# 3-way, mirrored log
+# Single log failure, replace
+lvcreate --mirrorlog mirrored -m 2 --ig -L 1 -n 3way $vg \
+    "$dev1" "$dev2" "$dev3" "$dev4":0 "$dev5":0
+aux disable_dev "$dev4"
+echo y | lvconvert --repair $vg/3way 2>&1 | tee 3way.out
+lvs -a -o +devices $vg | not grep unknown
+not grep "WARNING: Failed" 3way.out
+vgreduce --removemissing $vg
+check mirror $vg 3way
+aux enable_dev "$dev4"
+
+vgremove -ff $vg; vgcreate -c n $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+
+# 3-way, disk log
+# multiple failures, partial replace
+lvcreate --mirrorlog disk -m 2 --ig -L 1 -n 3way $vg "$dev1" "$dev2" "$dev3" "$dev4"
+aux disable_dev "$dev1" "$dev2"
+echo y | lvconvert --repair $vg/3way 2>&1 | tee 3way.out
+grep "WARNING: Failed" 3way.out
+lvs -a -o +devices $vg | not grep unknown
+vgreduce --removemissing $vg
+check mirror $vg 3way
+aux enable_dev "$dev1" "$dev2"
+lvchange -a n $vg/3way
+
+vgremove -ff $vg; vgcreate -c n $vg "$dev1" "$dev2" "$dev3"
+
+lvcreate --mirrorlog disk -m 1 --ig -L 1 -n 2way $vg "$dev1" "$dev2" "$dev3"
+aux disable_dev "$dev1"
+echo y | lvconvert --repair $vg/2way 2>&1 | tee 2way.out
+grep "WARNING: Failed" 2way.out
+lvs -a -o +devices $vg | not grep unknown
+vgreduce --removemissing $vg
+check mirror $vg 2way
+aux enable_dev "$dev1" "$dev2"
+lvchange -a n $vg/2way
+
+vgremove -ff $vg; vgcreate -c n $vg "$dev1" "$dev2" "$dev3" "$dev4"
+
+# Test repair of inactive mirror with log failure
+#  Replacement should fail, but covert should succeed (switch to corelog)
+lvcreate -m 2 --ig -l 2 -n mirror2 $vg "$dev1" "$dev2" "$dev3" "$dev4":0
+vgchange -a n $vg
+pvremove -ff -y "$dev4"
+echo 'y' | lvconvert -y --repair $vg/mirror2
+check mirror $vg mirror2
+vgs $vg
diff --git a/test/shell/lvconvert-repair-snapshot.sh b/test/shell/lvconvert-repair-snapshot.sh
new file mode 100644 (file)
index 0000000..786b950
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_vg 5
+aux lvmconf 'allocation/maximise_cling = 0'
+aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1'
+
+lvcreate -m 3 --ig -L 2M -n 4way $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5":0
+lvcreate -s $vg/4way -L 2M -n snap
+
+aux disable_dev "$dev2" "$dev4"
+echo n | lvconvert --repair $vg/4way 2>&1 | tee 4way.out
+lvs -a -o +devices $vg | not grep unknown
+vgreduce --removemissing $vg
+aux enable_dev "$dev2" "$dev4"
+lvs -a -o +devices $vg
+check mirror $vg 4way "$dev5"
diff --git a/test/shell/lvconvert-repair-transient-dmeventd.sh b/test/shell/lvconvert-repair-transient-dmeventd.sh
new file mode 100644 (file)
index 0000000..ac687eb
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/sh
+# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_vg 5
+aux prepare_dmeventd
+
+lvcreate -m 3 --ig -L 1 -n 4way $vg
+lvchange --monitor y $vg/4way
+aux disable_dev "$dev2" "$dev4"
+mkfs.ext3 $DM_DEV_DIR/$vg/4way
+aux enable_dev "$dev2" "$dev4"
+sleep 3
+lvs -a -o +devices $vg | not grep unknown
+check mirror $vg 4way
+check mirror_legs $vg 4way 2
+lvs -a -o +devices $vg | not grep mimage_1
+lvs -a -o +devices $vg | not grep mimage_3
+
+vgremove -f $vg
diff --git a/test/shell/lvconvert-repair-transient.sh b/test/shell/lvconvert-repair-transient.sh
new file mode 100644 (file)
index 0000000..beacf89
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_vg 5
+
+lvcreate -m 3 --ig -L 1 -n 4way $vg
+aux disable_dev "$dev2" "$dev4"
+mkfs.ext3 $DM_DEV_DIR/$vg/4way &
+sleep 1
+aux enable_dev "$dev2" "$dev4"
+echo n | lvconvert --repair $vg/4way 2>&1 | tee 4way.out
+lvs -a -o +devices | not grep unknown
+vgreduce --removemissing $vg
+check mirror $vg 4way
+lvchange -a n $vg/4way
+wait
+
+vgremove -f $vg
diff --git a/test/shell/lvconvert-repair.sh b/test/shell/lvconvert-repair.sh
new file mode 100644 (file)
index 0000000..51bc9de
--- /dev/null
@@ -0,0 +1,140 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+recreate_vg_()
+{
+       vgremove -ff $vg
+       vgcreate -c n $vg $(cat DEVICES)
+}
+
+aux lvmconf 'allocation/maximise_cling = 0'
+aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1'
+
+# fail multiple devices
+
+# 4-way, disk log => 2-way, disk log
+aux prepare_vg 8
+lvcreate -m 3 --ig -L 1 -n 4way $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5":0
+aux disable_dev "$dev2" "$dev4"
+echo n | lvconvert --repair $vg/4way 2>&1 | tee 4way.out
+lvs -a -o +devices $vg | not grep unknown
+vgreduce --removemissing $vg
+aux enable_dev "$dev2" "$dev4"
+check mirror $vg 4way "$dev5"
+
+# 3-way, disk log => linear
+recreate_vg_
+lvcreate -m 2 --ig -L 1 -n 3way $vg
+aux disable_dev "$dev1" "$dev2"
+echo n | lvconvert --repair $vg/3way
+check linear $vg 3way
+lvs -a -o +devices $vg | not grep unknown
+lvs -a -o +devices $vg | not grep mlog
+dmsetup ls | grep $PREFIX | not grep mlog
+vgreduce --removemissing $vg
+aux enable_dev "$dev1" "$dev2"
+check linear $vg 3way
+
+# fail just log and get it removed
+
+# 3-way, disk log => 3-way, core log
+recreate_vg_
+lvcreate -m 2 --ig -L 1 -n 3way $vg "$dev1" "$dev2" "$dev3" "$dev4":0
+aux disable_dev "$dev4"
+echo n | lvconvert --repair $vg/3way
+check mirror $vg 3way core
+lvs -a -o +devices $vg | not grep unknown
+lvs -a -o +devices $vg | not grep mlog
+dmsetup ls | grep $PREFIX | not grep mlog
+vgreduce --removemissing $vg
+aux enable_dev "$dev4"
+
+# 3-way, mirrored log => 3-way, core log
+recreate_vg_
+lvcreate -m 2 --mirrorlog mirrored --ig -L 1 -n 3way $vg \
+    "$dev1" "$dev2" "$dev3" "$dev4":0 "$dev5":0
+aux disable_dev "$dev4" "$dev5"
+echo n | lvconvert --repair $vg/3way
+check mirror $vg 3way core
+lvs -a -o +devices $vg | not grep unknown
+lvs -a -o +devices $vg | not grep mlog
+dmsetup ls | grep $PREFIX | not grep mlog
+vgreduce --removemissing $vg
+aux enable_dev "$dev4" "$dev5"
+
+# 2-way, disk log => 2-way, core log
+recreate_vg_
+lvcreate -m 1 --ig -L 1 -n 2way $vg "$dev1" "$dev2" "$dev3":0
+aux disable_dev "$dev3"
+echo n | lvconvert --repair $vg/2way
+check mirror $vg 2way core
+lvs -a -o +devices $vg | not grep unknown
+lvs -a -o +devices $vg | not grep mlog
+vgreduce --removemissing $vg
+aux enable_dev "$dev3"
+
+# fail single devices
+
+recreate_vg_
+vgreduce $vg "$dev4"
+
+lvcreate -m 1 --ig -L 1 -n mirror $vg
+lvchange -a n $vg/mirror
+vgextend $vg "$dev4"
+aux disable_dev "$dev1"
+lvchange --partial -a y $vg/mirror
+
+not vgreduce -v --removemissing $vg
+lvconvert -y --repair $vg/mirror
+vgreduce --removemissing $vg
+
+aux enable_dev "$dev1"
+vgextend $vg "$dev1"
+aux disable_dev "$dev2"
+lvconvert -y --repair $vg/mirror
+vgreduce --removemissing $vg
+
+aux enable_dev "$dev2"
+vgextend $vg "$dev2"
+aux disable_dev "$dev3"
+lvconvert -y --repair $vg/mirror
+vgreduce --removemissing $vg
+aux enable_dev "$dev3"
+vgextend $vg "$dev3"
+lvremove -ff $vg
+
+if aux target_at_least dm-raid 1 1 0; then
+       # RAID5 single replace
+       lvcreate --type raid5 -i 2 -l 2 -n $lv1 $vg "$dev1" "$dev2" "$dev3"
+       aux wait_for_sync $vg $lv1
+       aux disable_dev "$dev3"
+       lvconvert -y --repair $vg/$lv1
+       vgreduce --removemissing $vg
+       aux enable_dev "$dev3"
+       vgextend $vg "$dev3"
+       lvremove -ff $vg
+
+       # RAID6 double replace
+       lvcreate --type raid5 -i 3 -l 2 -n $lv1 $vg \
+           "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+       aux wait_for_sync $vg $lv1
+       aux disable_dev "$dev4" "$dev5"
+       lvconvert -y --repair $vg/$lv1
+       vgreduce --removemissing $vg
+       aux enable_dev "$dev4"
+       aux enable_dev "$dev5"
+       vgextend $vg "$dev4" "$dev5"
+       lvremove -ff $vg
+fi
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-thin.sh b/test/shell/lvconvert-thin.sh
new file mode 100644 (file)
index 0000000..97ccc09
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+#
+# Main
+#
+aux have_thin 1 0 0 || skip
+
+aux prepare_pvs 4 64
+
+vgcreate $vg -s 64K $(cat DEVICES)
+
+# create mirrored LVs for data and metadata volumes
+lvcreate -aey -l8 -m1 --mirrorlog core -n $lv1 $vg
+lvcreate -aey -l4 -m1 --mirrorlog core -n $lv2 $vg
+
+lvconvert -c 64K --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
+
+lvcreate -V10M -T $vg/$lv1 --name $lv3
+
+# check lvrename work properly
+lvrename $vg/$lv1  $vg/pool
+check lv_field $vg/pool name "pool"
+
+lvrename $vg/$lv3  $vg/$lv4
+check lv_field $vg/$lv4 name "$lv4"
+
+# not yet supported conversions
+not lvconvert -m 1 $vg/pool
+not lvconvert -m 1 $vg/$lv3
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-twostep.sh b/test/shell/lvconvert-twostep.sh
new file mode 100644 (file)
index 0000000..c45e7bc
--- /dev/null
@@ -0,0 +1,26 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_vg 4
+
+lvcreate -m 1 --mirrorlog disk --ig -L 1 -n mirror $vg
+not lvconvert -m 2 --mirrorlog core $vg/mirror "$dev3" 2>&1 | tee errs
+grep "two steps" errs
+
+lvconvert -m 2 $vg/mirror "$dev3"
+lvconvert --mirrorlog core $vg/mirror
+not lvconvert -m 1 --mirrorlog disk $vg/mirror "$dev3" 2>&1 | tee errs
+grep "two steps" errs
+
+not lvconvert -m 1 --mirrorlog mirrored $vg/mirror "$dev3" "$dev4" 2>&1 | tee errs
+grep "two steps" errs
diff --git a/test/shell/lvcreate-large-raid.sh b/test/shell/lvcreate-large-raid.sh
new file mode 100644 (file)
index 0000000..8768bb3
--- /dev/null
@@ -0,0 +1,71 @@
+#!/bin/sh
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# 'Exercise some lvcreate diagnostics'
+
+. lib/test
+
+aux target_at_least dm-raid 1 1 0 || skip
+
+aux prepare_vg 5
+
+lvcreate -s -l 20%FREE -n $lv1 $vg --virtualsize 256T
+lvcreate -s -l 20%FREE -n $lv2 $vg --virtualsize 256T
+lvcreate -s -l 20%FREE -n $lv3 $vg --virtualsize 256T
+lvcreate -s -l 20%FREE -n $lv4 $vg --virtualsize 256T
+lvcreate -s -l 20%FREE -n $lv5 $vg --virtualsize 256T
+
+#FIXME this should be 1024T
+#check lv_field $vg/$lv size "128.00m"
+
+aux lvmconf 'devices/filter = [ "a/dev\/mapper\/.*$/", "a/dev\/LVMTEST/", "r/.*/" ]'
+
+pvcreate $DM_DEV_DIR/$vg/$lv[12345]
+vgcreate -c n $vg1 $DM_DEV_DIR/$vg/$lv[12345]
+
+# bz837927 START
+
+#
+# Create large RAID LVs
+#
+# We need '--nosync' or our virtual devices won't work
+lvcreate --type raid1 -m 1 -L 200T -n $lv1 $vg1 --nosync
+check lv_field $vg1/$lv1 size "200.00t"
+lvremove -ff $vg1
+
+for segtype in raid4 raid5 raid6; do
+        lvcreate --type $segtype -i 3 -L 750T -n $lv1 $vg1 --nosync
+        check lv_field $vg1/$lv1 size "750.00t"
+        lvremove -ff $vg1
+done
+
+#
+# Convert large linear to RAID1 (belong in different test script?)
+#
+lvcreate -L 200T -n $lv1 $vg1
+# Need to deactivate or the up-convert will start sync'ing
+lvchange -an $vg1/$lv1
+lvconvert --type raid1 -m 1 $vg1/$lv1
+check lv_field $vg1/$lv1 size "200.00t"
+lvremove -ff $vg1
+
+#
+# Extending large RAID LV (belong in different script?)
+#
+lvcreate --type raid1 -m 1 -L 200T -n $lv1 $vg1 --nosync
+check lv_field $vg1/$lv1 size "200.00t"
+lvextend -L +200T $vg1/$lv1
+check lv_field $vg1/$lv1 size "400.00t"
+lvremove -ff $vg1
+
+# bz837927 END
+
+lvremove -ff $vg
diff --git a/test/shell/lvcreate-large-raid10.sh b/test/shell/lvcreate-large-raid10.sh
new file mode 100644 (file)
index 0000000..c9d4a2a
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/sh
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# 'Exercise some lvcreate diagnostics'
+
+. lib/test
+
+aux target_at_least dm-raid 1 3 0 || skip
+
+aux prepare_vg 5
+
+lvcreate -s -l 20%FREE -n $lv1 $vg --virtualsize 256T
+lvcreate -s -l 20%FREE -n $lv2 $vg --virtualsize 256T
+lvcreate -s -l 20%FREE -n $lv3 $vg --virtualsize 256T
+lvcreate -s -l 20%FREE -n $lv4 $vg --virtualsize 256T
+lvcreate -s -l 20%FREE -n $lv5 $vg --virtualsize 256T
+
+aux lvmconf 'devices/filter = [ "a/dev\/mapper\/.*$/", "a/dev\/LVMTEST/", "r/.*/" ]'
+
+pvcreate $DM_DEV_DIR/$vg/$lv[12345]
+vgcreate -c n $vg1 $DM_DEV_DIR/$vg/$lv[12345]
+
+#
+# Create large RAID LVs
+#
+# We need '--nosync' or our virtual devices won't work
+
+lvcreate --type raid10 -m 1 -i 2 -L 200T -n $lv1 $vg1 --nosync
+check lv_field $vg1/$lv1 size "200.00t"
+lvremove -ff $vg1
+
+lvremove -ff $vg
diff --git a/test/shell/lvcreate-large.sh b/test/shell/lvcreate-large.sh
new file mode 100644 (file)
index 0000000..b61ccca
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/sh
+# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# 'Exercise some lvcreate diagnostics'
+
+. lib/test
+
+aux prepare_vg 4
+
+lvcreate -s -l 100%FREE -n $lv $vg --virtualsize 1024T
+
+#FIXME this should be 1024T
+#check lv_field $vg/$lv size "128.00m"
+
+aux lvmconf 'devices/filter = [ "a/dev\/mapper\/.*$/", "a/dev\/LVMTEST/", "r/.*/" ]'
+
+pvcreate $DM_DEV_DIR/$vg/$lv
+vgcreate -c n $vg1 $DM_DEV_DIR/$vg/$lv
+
+lvcreate -l 100%FREE -n $lv1 $vg1
+check lv_field $vg1/$lv1 size "1024.00t"
+lvresize -f -l 72%VG $vg1/$lv1
+check lv_field $vg1/$lv1 size "737.28t"
+lvremove -ff $vg1/$lv1
+
+lvcreate -l 100%VG -n $lv1 $vg1
+check lv_field $vg1/$lv1 size "1024.00t"
+lvresize -f -l 72%VG $vg1/$lv1
+check lv_field $vg1/$lv1 size "737.28t"
+lvremove -ff $vg1/$lv1
+
+lvremove -ff $vg/$lv
diff --git a/test/shell/lvcreate-mirror.sh b/test/shell/lvcreate-mirror.sh
new file mode 100644 (file)
index 0000000..1f95387
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+aux prepare_vg 5 80
+aux lvmconf 'allocation/maximise_cling = 0'
+aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1'
+
+# 2-way mirror with corelog, 2 PVs
+lvcreate -l2 -m1 --mirrorlog core -n $lv1 $vg "$dev1" "$dev2"
+check mirror_images_redundant $vg $lv1
+lvremove -ff $vg
+
+# 2-way mirror with disklog, 3 PVs
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0-1
+check mirror_images_redundant $vg $lv1
+check mirror_log_on $vg $lv1 "$dev3"
+lvremove -ff $vg
+
+# 3-way mirror with disklog, 4 PVs
+lvcreate -l2 -m2 --mirrorlog disk -n $lv1 $vg "$dev1" "$dev2" "$dev4" "$dev3":0-1
+check mirror_images_redundant $vg $lv1
+check mirror_log_on $vg $lv1 "$dev3"
+lvremove -ff $vg
+
+# lvcreate --nosync is in 100% sync after creation (bz429342)
+lvcreate -l2 -m1 --nosync -n $lv1 $vg "$dev1" "$dev2" "$dev3":0-1 2>out
+grep "New mirror won't be synchronised." out
+lvs -o copy_percent --noheadings $vg/$lv1 | grep 100.00
+lvremove -ff $vg
+
+# creating 2-way mirror with disklog from 2 PVs fails
+not lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2"
diff --git a/test/shell/lvcreate-operation.sh b/test/shell/lvcreate-operation.sh
new file mode 100644 (file)
index 0000000..0ef3138
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# 'Exercise some lvcreate diagnostics'
+
+. lib/test
+
+cleanup_lvs() {
+       lvremove -ff $vg
+       (dm_table | not grep $vg) || \
+               die "ERROR: lvremove did leave some some mappings in DM behind!"
+}
+
+aux prepare_pvs 2
+aux pvcreate --metadatacopies 0 "$dev1"
+aux vgcreate -c n $vg $(cat DEVICES)
+
+# ---
+# Create snapshots of LVs on --metadatacopies 0 PV (bz450651)
+lvcreate -n$lv1 -l4 $vg "$dev1"
+lvcreate -n$lv2 -l4 -s $vg/$lv1
+lvcreate -n$lv3 -l4 --permission r -s $vg/$lv1
+cleanup_lvs
+
+# ---
+# Create mirror on two devices with mirrored log using --alloc anywhere
+lvcreate -m 1 -l4 -n $lv1 --mirrorlog mirrored $vg --alloc anywhere "$dev1" "$dev2"
+cleanup_lvs
+
+# --
+# Create mirror on one dev with mirrored log using --alloc anywhere, should fail
+not lvcreate -m 1 -l4 -n $lv1 --mirrorlog mirrored $vg --alloc anywhere "$dev1"
+cleanup_lvs
diff --git a/test/shell/lvcreate-pvtags.sh b/test/shell/lvcreate-pvtags.sh
new file mode 100644 (file)
index 0000000..806fff1
--- /dev/null
@@ -0,0 +1,48 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_pvs 3
+aux lvmconf 'allocation/maximise_cling = 0'
+aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1'
+
+# not required, just testing
+aux pvcreate --metadatacopies 0 "$dev1"
+
+vgcreate -c n $vg $(cat DEVICES)
+pvchange --addtag fast $(cat DEVICES)
+
+# 3 stripes with 3 PVs (selected by tag, @fast) is fine
+lvcreate -l3 -i3 $vg @fast
+
+# too many stripes(4) for 3 PVs
+not lvcreate -l4 -i4 $vg @fast
+
+# 2 stripes is too many with just one PV
+not lvcreate -l2 -i2 $vg $DM_DEV_DIR/mapper/pv1
+
+# lvcreate mirror
+lvcreate -l1 -m1 $vg @fast
+
+# lvcreate mirror w/corelog
+lvcreate -l1 -m2 --corelog $vg @fast
+
+# lvcreate mirror w/no free PVs
+not lvcreate -l1 -m2 $vg @fast
+
+# lvcreate mirror (corelog, w/no free PVs)
+not lvcreate -l1 -m3 --corelog $vg @fast
+
+# lvcreate mirror with a single PV arg
+not lvcreate -l1 -m1 --corelog $vg "$dev1"
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-raid.sh b/test/shell/lvcreate-raid.sh
new file mode 100644 (file)
index 0000000..05c7428
--- /dev/null
@@ -0,0 +1,49 @@
+#!/bin/sh
+# Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+########################################################
+# MAIN
+########################################################
+aux target_at_least dm-raid 1 1 0 || skip
+
+aux prepare_pvs 6 20  # 6 devices for RAID10 (2-mirror,3-stripe) test
+vgcreate -c n -s 512k $vg $(cat DEVICES)
+
+###########################################
+# Create, wait for sync, remove tests
+###########################################
+
+# Create RAID1 (implicit 2-way)
+lvcreate --type raid1 -l 2 -n $lv1 $vg
+aux wait_for_sync $vg $lv1
+lvremove -ff $vg
+
+# Create RAID1 (explicit 2-way)
+lvcreate --type raid1 -m 1 -l 2 -n $lv1 $vg
+aux wait_for_sync $vg $lv1
+lvremove -ff $vg
+
+# Create RAID1 (explicit 3-way)
+lvcreate --type raid1 -m 2 -l 2 -n $lv1 $vg
+aux wait_for_sync $vg $lv1
+lvremove -ff $vg
+
+# Create RAID 4/5/6 (explicit 3-stripe + parity devs)
+for i in raid4 \
+       raid5 raid5_ls raid5_la raid5_rs raid5_ra \
+       raid6 raid6_zr raid6_nr raid6_nc; do
+
+       lvcreate --type $i -l 3 -i 3 -n $lv1 $vg
+       aux wait_for_sync $vg $lv1
+       lvremove -ff $vg
+done
diff --git a/test/shell/lvcreate-raid10.sh b/test/shell/lvcreate-raid10.sh
new file mode 100644 (file)
index 0000000..63d086f
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/sh
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+########################################################
+# MAIN
+########################################################
+aux target_at_least dm-raid 1 3 0 || skip
+
+aux prepare_pvs 6 20  # 6 devices for RAID10 (2-mirror,3-stripe) test
+vgcreate -c n -s 512k $vg $(cat DEVICES)
+
+#
+# Create RAID10:
+#
+
+
+# Should not allow more than 2-way mirror
+not lvcreate --type raid10 -m 2 -i 2 -l 2 -n $lv1 $vg
+
+# 2-way mirror, 2-stripes
+lvcreate --type raid10 -m 1 -i 2 -l 2 -n $lv1 $vg
+aux wait_for_sync $vg $lv1
+lvremove -ff $vg
+
+# 2-way mirror, 3-stripes
+lvcreate --type raid10 -m 1 -i 3 -l 3 -n $lv1 $vg
+aux wait_for_sync $vg $lv1
+lvremove -ff $vg
+
+#
+# FIXME: Add tests that specify particular PVs to use for creation
+#
diff --git a/test/shell/lvcreate-repair.sh b/test/shell/lvcreate-repair.sh
new file mode 100644 (file)
index 0000000..8971536
--- /dev/null
@@ -0,0 +1,99 @@
+#!/bin/sh
+# Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_vg 3
+
+# fail multiple devices
+for i in "$dev1" "$dev2" "$dev3" ; do
+       for j in "$dev2" "$dev3" ; do
+               if test "$i" = "$j" ; then continue ; fi
+
+               vgremove -ff $vg
+               vgcreate $vg "$dev1" "$dev2" "$dev3"
+               # exit 1
+
+               lvcreate -l1 -n $lv1 $vg "$dev1"
+
+               aux disable_dev "$i" "$j"
+
+               vgreduce --removemissing --force $vg
+
+               # check if reduced device was removed
+               test "$i" = "$dev1" && dm_table | not egrep "$vg-$lv1: *[^ ]+"
+
+               lvcreate -l1 -n $lv2 $vg
+
+               test "$i" != "$dev1" && check lv_exists $vg $lv1
+               check lv_exists $vg $lv2
+
+               aux enable_dev "$i" "$j"
+               vgscan
+
+               test "$i" != "$dev1" && check lv_exists $vg $lv1
+               check lv_exists $vg $lv2
+       done
+done
+
+vgremove -ff $vg
+vgcreate $vg "$dev1" "$dev2" "$dev3"
+
+# use tricky 'dd'
+for i in "$dev1" "$dev2" "$dev3" ; do
+       for j in "$dev2" "$dev3" ; do
+
+               if test "$i" = "$j" ; then continue ; fi
+
+               dd if="$i" of=backup_i bs=256K count=1
+               dd if="$j" of=backup_j bs=256K count=1
+
+               lvcreate -l1 -n $lv1 $vg "$dev1"
+
+               dd if=backup_j of="$j" bs=256K count=1
+               dd if=backup_i of="$i" bs=256K count=1
+
+               check lv_exists $vg $lv1
+               # mda should be now consistent
+               lvremove -f $vg/$lv1
+       done
+done
+
+
+# confuse lvm with active LV left behind
+dd if="$dev1" of=backup_i bs=256K count=1
+dd if="$dev2" of=backup_j bs=256K count=1
+
+lvcreate -l1 $vg "$dev1"
+
+dd if=backup_j of="$dev2" bs=256K count=1
+dd if=backup_i of="$dev1" bs=256K count=1
+
+# CHECKME: following command writes here:
+# vgreduce --removemissing --force $vg
+#
+# WARNING: Inconsistent metadata found for VG LVMTESTvg - updating to use version 2
+# Volume group "LVMTESTvg" is already consistent
+
+# dirty game
+dd if=/dev/zero of="$dev3" bs=256K count=1
+aux notify_lvmetad "$dev3" # udev be watching you
+
+vgreduce --removemissing --force $vg
+
+# FIXME: here is LV1 left active - but metadata does not know about it
+# and lvcreate does not check whether such device exists in the table
+# so it ends with: 
+#
+# device-mapper: create ioctl failed: Device or resource busy
+# Failed to activate new LV.
+
+should lvcreate -l1 $vg "$dev1"
diff --git a/test/shell/lvcreate-small-snap.sh b/test/shell/lvcreate-small-snap.sh
new file mode 100644 (file)
index 0000000..9b43868
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_pvs 3
+
+vgcreate -c n -s 1k $vg $(cat DEVICES)
+
+lvcreate -n one -l 10 $vg
+lvcreate -s -l 8 -n snapA $vg/one
+lvcreate -s -c 4k -l 8 -n snapX1 $vg/one
+lvcreate -s -c 8k -l 16 -n snapX2 $vg/one
+
+# Check that snapshots that are too small are caught with correct error.
+not lvcreate -s -c 8k -l 8 -n snapX3 $vg/one 2>&1 | tee lvcreate.out
+not grep "suspend origin one" lvcreate.out
+grep "Unable to create a snapshot" lvcreate.out
+
+not lvcreate -s -l 4 -n snapB $vg/one 2>&1 | tee lvcreate.out
+not grep "suspend origin one" lvcreate.out
+grep "Unable to create a snapshot" lvcreate.out
diff --git a/test/shell/lvcreate-striped-mirror.sh b/test/shell/lvcreate-striped-mirror.sh
new file mode 100644 (file)
index 0000000..9a55a97
--- /dev/null
@@ -0,0 +1,65 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+aux prepare_vg 9
+
+lvcreate -i2 -l2 -m1 --mirrorlog core -n $lv1 $vg 2>&1 | tee log
+not grep "Rounding" log
+check mirror_images_redundant $vg $lv1
+lvremove -ff $vg
+
+lvcreate -i2 -l4 -m1 --mirrorlog core -n $lv1 $vg 2>&1 | tee log
+not grep "Rounding" log
+check mirror_images_redundant $vg $lv1
+lvremove -ff $vg
+
+lvcreate -i3 -l3 -m1 --mirrorlog core -n $lv1 $vg 2>&1 | tee log
+not grep "Rounding" log
+check mirror_images_redundant $vg $lv1
+lvremove -ff $vg
+
+lvcreate -i4 -l4 -m1 --mirrorlog core -n $lv1 $vg 2>&1 | tee log
+not grep "Rounding" log
+check mirror_images_redundant $vg $lv1
+lvremove -ff $vg
+
+
+lvcreate -i2 -l2 -m2 --mirrorlog core -n $lv1 $vg 2>&1 | tee log
+not grep "Rounding" log
+check mirror_images_redundant $vg $lv1
+lvremove -ff $vg
+
+lvcreate -i3 -l3 -m2 --mirrorlog core -n $lv1 $vg 2>&1 | tee log
+not grep "Rounding" log
+check mirror_images_redundant $vg $lv1
+lvremove -ff $vg
+
+lvcreate -i2 -l2 -m3 --mirrorlog core -n $lv1 $vg 2>&1 | tee log
+not grep "Rounding" log
+check mirror_images_redundant $vg $lv1
+lvremove -ff $vg
+
+lvcreate -i3 -l2 -m2 --mirrorlog core -n $lv1 $vg 2>&1 | tee log
+grep "Rounding size (2 extents) up to .* (3 extents)" log
+lvremove -ff $vg
+
+lvcreate -i3 -l4 -m2 --mirrorlog core -n $lv1 $vg 2>&1 | tee log
+grep "Rounding size (4 extents) up to .* (6 extents)" log
+lvremove -ff $vg
+
+lvcreate -i3 -l4 -m1 --mirrorlog core -n $lv1 $vg 2>&1 | tee log
+grep "Rounding size (4 extents) up to .* (6 extents)" log
+lvremove -ff $vg
+
+lvcreate -i4 -l4 -m1 --mirrorlog core -n $lv1 $vg 2>&1 | tee log
+not grep "Rounding" log
+lvremove -ff $vg
diff --git a/test/shell/lvcreate-thin-power2.sh b/test/shell/lvcreate-thin-power2.sh
new file mode 100644 (file)
index 0000000..882b05c
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+#
+# test support for non-power-of-2 thin chunk size
+#
+
+. lib/test
+
+#
+# Main
+#
+aux have_thin 1 4 0 || skip
+
+aux prepare_pvs 2 64
+
+vgcreate $vg -s 64K $(cat DEVICES)
+
+# create non-power-of-2 pool
+lvcreate -l100 -c 192 -T $vg/pool
+
+check lv_field $vg/pool discards "ignore"
+
+# check we cannot change discards settings
+not lvchange --discard passdown $vg/pool
+not lvchange --discard nopassdown $vg/pool
+
+# must be multiple of 64KB
+not lvcreate -l100 -c 168 -T $vg/pool1
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-thin-snap.sh b/test/shell/lvcreate-thin-snap.sh
new file mode 100644 (file)
index 0000000..23f91f9
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+check_lv_field_modules_()
+{
+       mod=$1
+       shift
+
+       for d in $*; do
+               check lv_field $vg/$d modules $mod
+       done
+}
+
+
+#
+# Main
+#
+aux have_thin 1 0 0 || skip
+
+aux prepare_pvs 2 64
+
+vgcreate $vg -s 64K $(cat DEVICES)
+
+lvcreate -L10M -V10M -T $vg/pool --name $lv1
+mkfs.ext4 $DM_DEV_DIR/$vg/$lv1
+# create thin snapshot of thin LV
+lvcreate -s $vg/$lv1
+# check snapshot filesystem was properly frozen before snapping
+fsck -p $DM_DEV_DIR/$vg/lvol0
+lvcreate -s $vg/$lv1 --name $lv2
+lvcreate -s $vg/$lv1 --name $vg/$lv3
+lvcreate --type snapshot $vg/$lv1
+lvcreate --type snapshot $vg/$lv1 --name $lv4
+lvcreate --type snapshot $vg/$lv1 --name $vg/$lv5
+
+# create old-style snapshot
+lvcreate -s -L10M --name oldsnap1 $vg/$lv2
+lvcreate -s -L10M --name oldsnap2 $vg/$lv2
+
+# thin snap of snap of snap...
+lvcreate -s --name sn1 $vg/$lv2
+lvcreate -s --name sn2 $vg/sn1
+lvcreate -s --name sn3 $vg/sn2
+lvcreate -s --name sn4 $vg/sn3
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-thin.sh b/test/shell/lvcreate-thin.sh
new file mode 100644 (file)
index 0000000..e651a81
--- /dev/null
@@ -0,0 +1,211 @@
+#!/bin/sh
+
+# Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# test currently needs to drop
+# 'return NULL' in _lv_create_an_lv after log_error("Can't create %s without using "
+
+. lib/test
+
+check_lv_field_modules_()
+{
+       mod=$1
+       shift
+
+       for d in $*; do
+               check lv_field $vg/$d modules $mod
+       done
+}
+
+
+#
+# Main
+#
+aux have_thin 1 0 0 || skip
+
+aux prepare_pvs 2 64
+
+vgcreate $vg -s 64K $(cat DEVICES)
+
+# Create named pool only
+lvcreate -l1 -T $vg/pool1
+lvcreate -l1 -T --thinpool $vg/pool2
+lvcreate -l1 -T --thinpool pool3 $vg
+lvcreate -l1 --type thin $vg/pool4
+lvcreate -l1 --type thin --thinpool $vg/pool5
+lvcreate -l1 --type thin --thinpool pool6 $vg
+lvcreate -l1 --type thin-pool $vg/pool7
+lvcreate -l1 --type thin-pool --thinpool $vg/pool8
+lvcreate -l1 --type thin-pool --thinpool pool9 $vg
+
+lvremove -ff $vg/pool1 $vg/pool2 $vg/pool3 $vg/pool4 $vg/pool5 $vg/pool6 $vg/pool7 $vg/pool8 $vg/pool9
+check vg_field $vg lv_count 0
+
+
+# Create default pool name
+lvcreate -l1 -T $vg
+lvcreate -l1 --type thin $vg
+lvcreate -l1 --type thin-pool $vg
+
+lvremove -ff $vg/lvol0 $vg/lvol1 $vg/lvol2
+check vg_field $vg lv_count 0
+
+
+# Create default pool and default thin LV
+lvcreate -l1 -V2G -T $vg
+lvcreate -l1 -V2G --type thin $vg
+
+lvremove -ff $vg
+
+
+# Create named pool and default thin LV
+lvcreate -L4M -V2G -T $vg/pool1
+lvcreate -L4M -V2G -T --thinpool $vg/pool2
+lvcreate -L4M -V2G -T --thinpool pool3 $vg
+lvcreate -L4M -V2G --type thin $vg/pool4
+lvcreate -L4M -V2G --type thin --thinpool $vg/pool5
+lvcreate -L4M -V2G --type thin --thinpool pool6 $vg
+
+check lv_exists $vg lvol0 lvol1 lvol2 lvol3 lvol4 lvol5
+lvremove -ff $vg
+
+
+# Create named pool and named thin LV
+lvcreate -L4M -V2G -T $vg/pool1 --name lv1
+lvcreate -L4M -V2G -T $vg/pool2 --name $vg/lv2
+lvcreate -L4M -V2G -T --thinpool $vg/pool3 --name lv3
+lvcreate -L4M -V2G -T --thinpool $vg/pool4 --name $vg/lv4
+lvcreate -L4M -V2G -T --thinpool pool5 --name lv5 $vg
+lvcreate -L4M -V2G -T --thinpool pool6 --name $vg/lv6 $vg
+
+check lv_exists $vg lv1 lv2 lv3 lv4 lv5 lv6
+lvremove -ff $vg
+
+
+lvcreate -L4M -V2G --type thin $vg/pool1 --name lv1
+lvcreate -L4M -V2G --type thin $vg/pool2 --name $vg/lv2
+lvcreate -L4M -V2G --type thin --thinpool $vg/pool3 --name lv3
+lvcreate -L4M -V2G --type thin --thinpool $vg/pool4 --name $vg/lv4
+lvcreate -L4M -V2G --type thin --thinpool pool5 --name lv5 $vg
+lvcreate -L4M -V2G --type thin --thinpool pool6 --name $vg/lv6 $vg
+
+check lv_exists $vg lv1 lv2 lv3 lv4 lv5 lv6
+lvremove -ff $vg
+
+
+# Create default thin LV in existing pool
+lvcreate -L4M -T $vg/pool
+lvcreate -V2G -T $vg/pool
+lvcreate -V2G -T --thinpool $vg/pool
+lvcreate -V2G -T --thinpool pool $vg
+lvcreate -V2G --type thin $vg/pool
+lvcreate -V2G --type thin --thinpool $vg/pool
+lvcreate -V2G --type thin --thinpool pool $vg
+
+check lv_exists $vg lvol0 lvol1 lvol2 lvol3 lvol4 lvol5
+
+
+# Create named thin LV in existing pool
+lvcreate -V2G -T $vg/pool --name lv1
+lvcreate -V2G -T $vg/pool --name $vg/lv2
+lvcreate -V2G -T --thinpool $vg/pool --name lv3
+lvcreate -V2G -T --thinpool $vg/pool --name $vg/lv4
+lvcreate -V2G -T --thinpool pool --name lv5 $vg
+lvcreate -V2G -T --thinpool pool --name $vg/lv6 $vg
+lvcreate -V2G --type thin $vg/pool --name lv7
+lvcreate -V2G --type thin $vg/pool --name $vg/lv8
+lvcreate -V2G --type thin --thinpool $vg/pool --name lv9
+lvcreate -V2G --type thin --thinpool $vg/pool --name $vg/lv10
+lvcreate -V2G --type thin --thinpool pool --name lv11 $vg
+lvcreate -V2G --type thin --thinpool pool --name $vg/lv12 $vg
+
+check lv_exists $vg lv1 lv2 lv3 lv4 lv5 lv6 lv7 lv8 lv9 lv10 lv11 lv12
+check vg_field $vg lv_count 19
+
+lvremove -ff $vg
+check vg_field $vg lv_count 0
+
+# Create thin snapshot of thinLV
+lvcreate -L10M -V10M -T $vg/pool --name lv1
+mkfs.ext4 $DM_DEV_DIR/$vg/lv1
+lvcreate -s $vg/lv1
+fsck -p $DM_DEV_DIR/$vg/lvol0
+lvcreate -s $vg/lv1 --name lv2
+lvcreate -s $vg/lv1 --name $vg/lv3
+lvcreate --type snapshot $vg/lv1
+lvcreate --type snapshot $vg/lv1 --name lv4
+lvcreate --type snapshot $vg/lv1 --name $vg/lv5
+
+check_lv_field_modules_ thin-pool lv1 lvol0 lv2 lv3 lvol1 lv4 lv5
+check vg_field $vg lv_count 8
+lvremove -ff $vg
+
+
+# Normal Snapshots of thinLV
+lvcreate -L4M -V2G -T $vg/pool --name lv1
+lvcreate -s $vg/lv1 -l1
+lvcreate -s $vg/lv1 -l1 --name lv2
+lvcreate -s $vg/lv1 -l1 --name $vg/lv3
+lvcreate -s lv1 -L4M --name $vg/lv4
+
+check_lv_field_modules_ snapshot lvol0 lv2 lv3 lv4
+check vg_field $vg lv_count 6
+
+lvremove -ff $vg
+check vg_field $vg lv_count 0
+
+lvdisplay $vg
+
+# Fail cases
+# Too small pool size (1 extent 64KB) for given chunk size
+not lvcreate --chunksize 256 -l1 -T $vg/pool1
+# Too small chunk size (min is 64KB -  128 sectors)
+not lvcreate --chunksize 32 -l1 -T $vg/pool1
+# Too large chunk size (max is 1GB)
+not lvcreate -L4M --chunksize 2G -T $vg/pool1
+
+lvcreate -L4M -V2G --name lv1 -T $vg/pool1
+# Origin name is not accepted
+not lvcreate -s $vg/lv1 -L4M -V2G --name $vg/lv4
+
+# Check we cannot create mirror and thin or thinpool together
+not lvcreate -T mirpool -L4M --alloc anywhere -m1 $vg
+not lvcreate --thinpool mirpool -L4M --alloc anywhere -m1 $vg
+
+vgremove -ff $vg
+
+# Test --poolmetadatasize range
+# allocating large devices for testing
+aux teardown_devs
+aux prepare_pvs 10 16500
+vgcreate $vg -s 64K $(cat DEVICES)
+
+lvcreate -L4M --chunksize 128 --poolmetadatasize 0 -T $vg/pool1 2>out
+grep "WARNING: Minimum" out
+# FIXME: metadata allocation fails, if PV doesn't have at least 16GB
+# i.e. pool metadata device cannot be multisegment
+lvcreate -L4M --chunksize 64k --poolmetadatasize 17G -T $vg/pool2 2>out
+grep "WARNING: Maximum" out
+check lv_field $vg/pool1_tmeta size "2.00m"
+check lv_field $vg/pool2_tmeta size "16.00g"
+lvremove -ff $vg
+
+# Test automatic calculation of pool metadata size
+lvcreate -L160G -T $vg/pool
+check lv_field $vg/pool lv_metadata_size "80.00m"
+check lv_field $vg/pool chunksize        "128.00k"
+lvremove -ff $vg/pool
+
+lvcreate -L10G --chunksize 256 -T $vg/pool1
+lvcreate -L60G --chunksize 1024 -T $vg/pool2
+check lv_field $vg/pool1_tmeta size "2.50m"
+check lv_field $vg/pool2_tmeta size "3.75m"
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-usage.sh b/test/shell/lvcreate-usage.sh
new file mode 100644 (file)
index 0000000..ddde401
--- /dev/null
@@ -0,0 +1,150 @@
+#!/bin/sh
+# Copyright (C) 2008-2011 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# 'Exercise some lvcreate diagnostics'
+
+. lib/test
+
+aux prepare_pvs 4
+aux pvcreate --metadatacopies 0 "$dev1"
+vgcreate -cn $vg $(cat DEVICES)
+
+# "lvcreate rejects repeated invocation (run 2 times) (bz178216)" 
+lvcreate -n $lv -l 4 $vg 
+not lvcreate -n $lv -l 4 $vg
+lvremove -ff $vg/$lv
+# try to remove it again - should fail (but not segfault)
+not lvremove -ff $vg/$lv
+
+# "lvcreate rejects a negative stripe_size"
+not lvcreate -L 64m -n $lv -i2 --stripesize -4 $vg 2>err;
+grep "Negative stripesize is invalid" err
+
+# 'lvcreate rejects a too-large stripesize'
+not lvcreate -L 64m -n $lv -i2 --stripesize 4294967291 $vg 2>err
+grep "Stripe size cannot be larger than" err
+
+# 'lvcreate w/single stripe succeeds with diagnostics to stdout' 
+lvcreate -L 64m -n $lv -i1 --stripesize 4 $vg 2> err | tee out
+grep "Ignoring stripesize argument with single stripe" out
+lvdisplay $vg 
+lvremove -ff $vg
+
+# 'lvcreate w/default (64KB) stripe size succeeds with diagnostics to stdout'
+lvcreate -L 64m -n $lv -i2 $vg > out
+grep "Using default stripesize" out
+lvdisplay $vg 
+check lv_field $vg/$lv stripesize "64.00k"
+lvremove -ff $vg
+
+# 'lvcreate rejects an invalid number of stripes' 
+not lvcreate -L 64m -n $lv -i129 $vg 2>err
+grep "Number of stripes (129) must be between 1 and 128" err
+
+# The case on lvdisplay output is to verify that the LV was not created.
+# 'lvcreate rejects an invalid stripe size'
+not lvcreate -L 64m -n $lv -i2 --stripesize 3 $vg 2>err
+grep "Invalid stripe size" err
+test -z "$(lvdisplay $vg)"
+
+# Setting max_lv works. (bz490298)
+lvremove -ff $vg
+vgchange -l 3 $vg
+lvcreate -l1 -n $lv1 $vg
+lvcreate -l1 -s -n $lv2 $vg/$lv1
+lvcreate -l1 -n $lv3 $vg
+not lvcreate -l1 -n $lv4 $vg
+
+lvremove -ff $vg/$lv3
+lvcreate -l1 -s -n $lv3 $vg/$lv1
+not lvcreate -l1 -n $lv4 $vg
+not lvcreate -l1 -m1 -n $lv4 $vg
+
+lvremove -ff $vg/$lv3
+lvcreate -l1 -m1 -n $lv3 $vg
+vgs -o +max_lv $vg
+not lvcreate -l1 -n $lv4 $vg
+not lvcreate -l1 -m1 -n $lv4 $vg
+
+lvconvert -m0 $vg/$lv3
+lvconvert -m2 -i 1 $vg/$lv3
+lvconvert -m1 $vg/$lv3
+
+not vgchange -l 2
+vgchange -l 4
+vgs $vg
+
+lvremove -ff $vg
+vgchange -l 0 $vg
+
+# lvcreate rejects invalid chunksize, accepts between 4K and 512K
+# validate origin_size
+vgremove -ff $vg
+vgcreate -cn $vg $(cat DEVICES)
+lvcreate -L 32m -n $lv1 $vg
+not lvcreate -L 8m -n $lv2 -s --chunksize 3k $vg/$lv1
+not lvcreate -L 8m -n $lv2 -s --chunksize 1024k $vg/$lv1
+lvcreate -L 8m -n $lv2 -s --chunksize 4k $vg/$lv1
+check lv_field $vg/$lv2 chunk_size "4.00k"
+check lv_field $vg/$lv2 origin_size "32.00m"
+lvcreate -L 8m -n $lv3 -s --chunksize 512k $vg/$lv1
+check lv_field $vg/$lv3 chunk_size "512.00k"
+check lv_field $vg/$lv3 origin_size "32.00m"
+lvremove -ff $vg
+vgchange -l 0 $vg
+
+# regionsize must be
+# - nonzero (bz186013)
+# - a power of 2 and a multiple of page size
+# - <= size of LV
+not lvcreate -L 32m -n $lv -R0 $vg 2>err
+grep "Non-zero region size must be supplied." err
+not lvcreate -L 32m -n $lv -R 11k $vg
+not lvcreate -L 32m -n $lv -R 1k $vg
+lvcreate -L 32m -n $lv --regionsize 128m  -m 1 $vg
+check lv_field $vg/$lv regionsize "32.00m"
+lvremove -ff $vg
+lvcreate -L 32m -n $lv --regionsize 4m -m 1 $vg
+check lv_field $vg/$lv regionsize "4.00m"
+lvremove -ff $vg
+
+# snapshot with virtual origin works
+lvcreate -s --virtualoriginsize 64m -L 32m -n $lv1 $vg
+lvrename $vg/$lv1 $vg/$lv2
+lvcreate -s --virtualoriginsize 64m -L 32m -n $lv1 $vg
+lvchange -a n $vg/$lv1
+lvremove -ff $vg/$lv1
+lvremove -ff $vg
+
+# readahead default (auto), none, #, auto
+lvcreate -L 32m -n $lv $vg
+check lv_field $vg/$lv lv_read_ahead "auto"
+lvremove -ff $vg
+lvcreate -L 32m -n $lv --readahead none $vg
+check lv_field $vg/$lv lv_read_ahead "0"
+check lv_field $vg/$lv lv_kernel_read_ahead "0"
+lvremove -ff $vg
+lvcreate -L 32m -n $lv --readahead 8k $vg
+check lv_field $vg/$lv lv_read_ahead "8.00k"
+check lv_field $vg/$lv lv_kernel_read_ahead "8.00k"
+lvremove -ff $vg
+lvcreate -L 32m -n $lv --readahead auto $vg
+check lv_field $vg/$lv lv_read_ahead "auto"
+check lv_field $vg/$lv lv_kernel_read_ahead "128.00k"
+lvremove -ff $vg
+lvcreate -L 32m -n $lv -i2 --stripesize 16k --readahead auto $vg
+check lv_field $vg/$lv lv_read_ahead "auto"
+check lv_field $vg/$lv lv_kernel_read_ahead "128.00k"
+lvremove -ff $vg
+lvcreate -L 32m -n $lv -i2 --stripesize 128k --readahead auto $vg
+check lv_field $vg/$lv lv_read_ahead "auto"
+check lv_field $vg/$lv lv_kernel_read_ahead "512.00k"
+lvremove -ff $vg
diff --git a/test/shell/lvextend-percent-extents.sh b/test/shell/lvextend-percent-extents.sh
new file mode 100644 (file)
index 0000000..1d59082
--- /dev/null
@@ -0,0 +1,106 @@
+#!/bin/sh
+# Copyright (C) 2008-2011 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# 'Check extents percentage arguments'
+
+. lib/test
+
+aux prepare_vg 2 128
+
+lvcreate -L 64m -n $lv $vg
+
+# 'lvextend rejects both size and extents without PVs'
+not lvextend -l 10 -L 64m $vg/$lv 2>err
+grep "Please specify either size or extents but not both." err
+
+# 'lvextend rejects both size and extents with PVs'
+not lvextend -l 10 -L 64m $vg/$lv "$dev1" 2>err
+grep "Please specify either size or extents but not both." err
+
+# 'lvextend accepts no size or extents but one PV - bz154691'
+lvextend $vg/$lv "$dev1" >out
+grep "Logical volume $lv successfully resized" out
+check pv_field "$dev1" pv_free "0"
+
+lvremove -f $vg/$lv
+
+# 'lvextend computes necessary free space correctly - bz213552'
+vgsize=$(get vg_field $vg vg_extent_count)
+lvcreate -l $vgsize  -n $lv $vg
+lvreduce -f -l $(( $vgsize / 2 )) $vg/$lv
+lvextend -l $vgsize $vg/$lv
+
+# 'Reset LV to original size'
+lvremove -f $vg/$lv
+lvcreate -L 64m -n $lv $vg
+
+# 'lvextend accepts no size but extents 100%PVS and two PVs - bz154691'
+lvextend -l +100%PVS $vg/$lv "$dev1" "$dev2" >out
+grep "Logical volume $lv successfully resized" out
+check pv_field "$dev1" pv_free "0"
+check pv_field "$dev2" pv_free "0"
+
+# Exercise the range overlap code.  Allocate every 2 extents.
+#
+#      Physical Extents
+#          1         2
+#012345678901234567890123
+#
+#aaXXaaXXaaXXaaXXaaXXaaXX - (a)llocated
+#rrrXXXrrrXXXrrrXXXrrrXXX - (r)ange on cmdline
+#ooXXXXXXoXXXooXXXXXXoXXX - (o)verlap of range and allocated
+#
+# Key: a - allocated
+#      F - free
+#      r - part of a range on the cmdline
+#      N - not on cmdline
+#
+# Create the LV with 12 extents, allocated every other 2 extents.
+# Then extend it, with a range of PVs on the cmdline of every other 3 extents.
+# Total number of extents should be 12 + overlap = 12 + 6 = 18.
+# Thus, total size for the LV should be 18 * 4M = 72M
+#
+# 'Reset LV to 12 extents, allocate every other 2 extents'
+create_pvs=$(for i in $(seq 0 4 20); do echo -n "$dev1:$i-$(($i + 1)) "; done)
+lvremove -f $vg/$lv
+lvcreate -l 12 -n $lv $vg $create_pvs
+check lv_field $vg/$lv lv_size "48.00m"
+
+# 'lvextend with partially allocated PVs and extents 100%PVS with PE ranges'
+extend_pvs=$(for i in $(seq 0 6 18); do echo -n "$dev1:$i-$(($i + 2)) "; done)
+lvextend -l +100%PVS $vg/$lv $extend_pvs >out
+grep "Logical volume $lv successfully resized" out
+check lv_field $vg/$lv lv_size "72.00m"
+
+# Simple seg_count validation; initially create the LV with half the # of
+# extents (should be 1 lv segment), extend it (should go to 2 segments),
+# then reduce (should be back to 1)
+# FIXME: test other segment fields such as seg_size, pvseg_start, pvseg_size
+lvremove -f $vg/$lv
+pe_count=$(get pv_field "$dev1" pv_pe_count)
+pe1=$(( $pe_count / 2 ))
+lvcreate -l $pe1 -n $lv $vg
+pesize=$(get lv_field $vg/$lv vg_extent_size --units b --nosuffix)
+segsize=$(( $pe1 * $pesize / 1024 / 1024 ))m
+check lv_field $vg/$lv seg_count "1"
+check lv_field $vg/$lv seg_start "0"
+check lv_field $vg/$lv seg_start_pe "0"
+#check lv_field $vg/$lv seg_size $segsize
+lvextend -l +$(( $pe_count * 1 )) $vg/$lv
+check lv_field $vg/$lv seg_count "2"
+lvreduce -f -l -$(( $pe_count * 1 )) $vg/$lv
+check lv_field $vg/$lv seg_count "1"
+
+# do not reduce to 0 extents
+lvremove -f $vg/$lv
+lvcreate -i2 -I 64k -l10 -n $lv $vg
+lvreduce -f -l1 $vg/$lv
+check lv_field $vg/$lv lv_size "8.00m"
diff --git a/test/shell/lvextend-snapshot-dmeventd.sh b/test/shell/lvextend-snapshot-dmeventd.sh
new file mode 100644 (file)
index 0000000..98bec19
--- /dev/null
@@ -0,0 +1,61 @@
+#!/bin/sh
+# Copyright (C) 2010-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+extend() {
+       lvextend --use-policies --config "activation { snapshot_autoextend_threshold = $1 }" $vg/snap
+}
+
+write_() {
+       dd if=/dev/zero of="$DM_DEV_DIR/$vg/snap" bs=1k count=$2 seek=$1
+}
+
+percent_() {
+       get lv_field $vg/snap snap_percent | cut -d. -f1
+}
+
+wait_for_change_() {
+       # dmeventd only checks every 10 seconds :(
+       for i in $(seq 1 15) ; do
+               test "$(percent_)" != "$1" && return
+               sleep 1
+       done
+
+       return 1  # timeout
+}
+
+aux prepare_dmeventd
+aux prepare_vg 2
+
+lvcreate -L16M -n base $vg
+lvcreate -s -L4M -n snap $vg/base
+
+write_ 0 1000
+test 24 -eq $(percent_)
+
+lvchange --monitor y $vg/snap
+
+write_ 1000 1700
+pre=$(percent_)
+wait_for_change_ $pre
+test $pre -gt $(percent_)
+
+# check that a second extension happens; we used to fail to extend when the
+# utilisation ended up between THRESH and (THRESH + 10)... see RHBZ 754198
+# (the utilisation after the write should be 57 %)
+
+write_ 2700 2000
+pre=$(percent_)
+wait_for_change_ $pre
+test $pre -gt $(percent_)
+
+vgremove -f $vg
diff --git a/test/shell/lvextend-snapshot-policy.sh b/test/shell/lvextend-snapshot-policy.sh
new file mode 100644 (file)
index 0000000..2f5d84b
--- /dev/null
@@ -0,0 +1,49 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+which mkfs.ext2 || skip
+
+extend() {
+       lvextend --use-policies --config "activation { snapshot_autoextend_threshold = $1 }" $vg/snap
+}
+
+write() {
+       mount "$DM_DEV_DIR/$vg/snap" mnt
+       dd if=/dev/zero of="mnt/file$1" bs=1k count=$2
+       umount mnt
+}
+
+percent() {
+       get lv_field $vg/snap snap_percent | cut -d. -f1
+}
+
+aux prepare_dmeventd
+aux prepare_vg 2
+
+lvcreate -l 8 -n base $vg
+mkfs.ext2 "$DM_DEV_DIR/$vg/base"
+
+lvcreate -s -l 4 -n snap $vg/base
+mkdir mnt
+
+write 1 4096
+pre=$(percent)
+extend 50
+test $pre -eq $(percent)
+
+write 2 4096
+pre=$(percent)
+extend 50
+test $pre -gt $(percent)
+
+vgremove -f $vg
diff --git a/test/shell/lvm-init.sh b/test/shell/lvm-init.sh
new file mode 100644 (file)
index 0000000..8eb7814
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+#
+# tests lvm initialization, and especially negative tests of error paths
+#
+
+. lib/test
+
+aux prepare_devs 5
+
+# invalid units
+not pvs --config 'global { units = "<" }'
diff --git a/test/shell/lvmcache-exercise.sh b/test/shell/lvmcache-exercise.sh
new file mode 100644 (file)
index 0000000..b1e2b92
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_pvs 5
+
+vgcreate $vg1 "$dev1"
+vgcreate $vg2 "$dev3"
+
+aux disable_dev "$dev1"
+pvscan
+vgcreate $vg1 "$dev2"
+aux enable_dev "$dev1"
+pvs
diff --git a/test/shell/lvmetad-disabled.sh b/test/shell/lvmetad-disabled.sh
new file mode 100644 (file)
index 0000000..41a3a19
--- /dev/null
@@ -0,0 +1,26 @@
+#!/bin/sh
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+test -e LOCAL_LVMETAD || skip
+kill $(cat LOCAL_LVMETAD)
+
+test -e $LVMETAD_PIDFILE && skip
+lvmetad
+test -e $LVMETAD_PIDFILE
+cp $LVMETAD_PIDFILE LOCAL_LVMETAD
+pvs 2>&1 | not grep "lvmetad is running"
+aux lvmconf "global/use_lvmetad = 0"
+pvs 2>&1 | grep "lvmetad is running"
+
+kill $(cat $LVMETAD_PIDFILE)
+not ls $LVMETAD_PIDFILE
diff --git a/test/shell/lvmetad-dump.sh b/test/shell/lvmetad-dump.sh
new file mode 100644 (file)
index 0000000..e49eb68
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+test -e LOCAL_LVMETAD || skip
+
+aux prepare_pvs 2
+vgcreate $vg1 $dev1 $dev2
+lvcreate -n bar -l 1 $vg1
+
+lvmetad_talk() {
+    if type -p socat >& /dev/null; then
+       socat "unix-connect:$1" -
+    elif echo | nc -U "$1"; then
+       nc -U "$1"
+    else
+       echo "WARNING: Neither socat nor nc -U seems to be available." 1>&2
+       echo "# DUMP FAILED"
+       return 1
+    fi
+}
+
+lvmetad_dump() {
+    (echo 'request="dump"'; echo '##') | lvmetad_talk "$@"
+}
+
+(echo | lvmetad_talk ./lvmetad.socket) || skip
+lvmetad_dump ./lvmetad.socket | tee lvmetad.txt
+
+grep $vg1 lvmetad.txt
diff --git a/test/shell/lvmetad-lvm1.sh b/test/shell/lvmetad-lvm1.sh
new file mode 100644 (file)
index 0000000..528eec2
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/sh
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+test -e LOCAL_LVMETAD || skip
+aux prepare_devs 2
+pvcreate --metadatatype 1 $dev1
+vgscan --cache
+pvs | grep $dev1
+vgcreate --metadatatype 1 $vg1 $dev1
+vgscan --cache
+vgs | grep $vg1
+pvs | grep $dev1
diff --git a/test/shell/lvmetad-pvs.sh b/test/shell/lvmetad-pvs.sh
new file mode 100644 (file)
index 0000000..80b421c
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_pvs 1 20000
+pvs $(cat DEVICES) | grep "$dev1"
+
+# check for PV size overflows
+pvs $(cat DEVICES) | grep 19.53g
+pvs $(cat DEVICES) | not grep 16.00e
diff --git a/test/shell/lvmetad-pvscan-cache.sh b/test/shell/lvmetad-pvscan-cache.sh
new file mode 100644 (file)
index 0000000..a27b6ad
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/sh
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+test -e LOCAL_LVMETAD || skip
+
+aux prepare_pvs 2
+
+vgcreate $vg1 $dev1 $dev2
+vgs | grep $vg1
+
+pvscan --cache
+
+vgs | grep $vg1
diff --git a/test/shell/lvmetad-restart.sh b/test/shell/lvmetad-restart.sh
new file mode 100644 (file)
index 0000000..10268c2
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/sh
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+test -e LOCAL_LVMETAD || skip
+aux prepare_pvs 2
+
+vgcreate $vg1 $dev1 $dev2
+vgs | grep $vg1
+
+kill $(cat LOCAL_LVMETAD)
+aux prepare_lvmetad
+
+vgs | grep $vg1
diff --git a/test/shell/lvmetad-test.sh b/test/shell/lvmetad-test.sh
new file mode 100644 (file)
index 0000000..7e801f1
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/sh
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_pvs 2
+
+vgcreate $vg1 $dev1 $dev2 --test
+vgs | not grep $vg1
+vgcreate $vg1 $dev1 $dev2
+vgs | grep $vg1
+
+lvcreate -n bar -l 1 $vg1 --test
+lvs | not grep bar
+lvcreate -n bar -l 1 $vg1
+lvs | grep bar
+
+lvremove $vg1/bar -f --test
+lvs | grep bar
+lvremove $vg1/bar -f
+lvs | not grep bar
+
+vgremove $vg1 --test
+vgs | grep $vg1
+vgremove $vg1
+vgs | not grep $vg1
diff --git a/test/shell/lvmetad-warning.sh b/test/shell/lvmetad-warning.sh
new file mode 100644 (file)
index 0000000..3a97a1b
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+test -e LOCAL_LVMETAD || skip
+aux prepare_pvs 2
+
+vgcreate $vg1 $dev1 $dev2
+lvchange -ay $vg1 2>&1 | not grep "Failed to connect"
+kill $(cat LOCAL_LVMETAD)
+lvchange -ay $vg1 2>&1 | grep "Failed to connect"
+lvchange -ay $vg1 --sysinit 2>&1 | not grep "Failed to connect"
+aux lvmconf 'global/use_lvmetad = 0'
+lvchange -ay $vg1 2>&1 | not grep "Failed to connect"
+lvchange -ay $vg1 --sysinit 2>&1 | not grep "Failed to connect"
+aux prepare_lvmetad
+lvchange -ay $vg1 2>&1 | not grep "Failed to connect"
+lvchange -ay $vg1 --sysinit 2>&1 | not grep "Failed to connect"
diff --git a/test/shell/lvresize-mirror.sh b/test/shell/lvresize-mirror.sh
new file mode 100644 (file)
index 0000000..a10f7cd
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_vg 5 80
+
+# extend 2-way mirror
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0-1
+lvchange -an $vg/$lv1
+lvextend -l+2 $vg/$lv1
+check mirror $vg $lv1 "$dev3"
+check mirror_images_contiguous $vg $lv1
+lvremove -ff $vg
+
+# reduce 2-way mirror
+lvcreate -l4 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0-1
+lvchange -an $vg/$lv1
+lvreduce -l-2 $vg/$lv1
+check mirror $vg $lv1 "$dev3"
+lvremove -ff $vg
+
+# extend 2-way mirror (cling if not contiguous)
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0-1
+lvcreate -l1 -n $lv2 $vg "$dev1"
+lvcreate -l1 -n $lv3 $vg "$dev2"
+lvchange -an $vg/$lv1
+lvextend -l+2 $vg/$lv1
+check mirror $vg $lv1 "$dev3"
+check mirror_images_clung $vg $lv1
+lvremove -ff $vg
diff --git a/test/shell/lvresize-raid.sh b/test/shell/lvresize-raid.sh
new file mode 100644 (file)
index 0000000..f999a31
--- /dev/null
@@ -0,0 +1,80 @@
+#!/bin/sh
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux target_at_least dm-raid 1 1 0 || skip
+
+aux prepare_vg 5 80
+
+# Extend a 2-way RAID1
+for deactivate in true false; do
+       lvcreate --type raid1 -m 1 -l 2 -n $lv1 $vg
+
+       if $deactivate; then
+               lvchange -an $vg/$lv1
+       fi
+
+       lvresize -l +2 $vg/$lv1
+
+       #check raid_images_contiguous $vg $lv1
+
+       lvremove -ff $vg
+done
+
+# Reduce 2-way RAID1
+for deactivate in true false; do
+       lvcreate --type raid1 -m 1 -l 4 -n $lv1 $vg
+
+       if $deactivate; then
+               lvchange -an $vg/$lv1
+       fi
+
+       should lvresize -y -l -2 $vg/$lv1
+
+       #check raid_images_contiguous $vg $lv1
+
+       lvremove -ff $vg
+done
+
+# Extend 3-striped RAID 4/5/6
+for i in 4 5 6 ; do
+       for deactivate in true false; do
+               lvcreate --type raid$i -i 3 -l 3 -n $lv1 $vg
+
+               if $deactivate; then
+                       lvchange -an $vg/$lv1
+               fi
+
+               lvresize -l +3 $vg/$lv1
+
+               #check raid_images_contiguous $vg $lv1
+
+               lvremove -ff $vg
+       done
+done
+
+# Reduce 3-striped RAID 4/5/6
+for i in 4 5 6 ; do
+       for deactivate in true false; do
+               lvcreate --type raid$i -i 3 -l 6 -n $lv1 $vg
+
+               if $deactivate; then
+                       lvchange -an $vg/$lv1
+               fi
+
+               should lvresize -y -l -3 $vg/$lv1
+
+               #check raid_images_contiguous $vg $lv1
+
+               lvremove -ff $vg
+       done
+done
diff --git a/test/shell/lvresize-raid10.sh b/test/shell/lvresize-raid10.sh
new file mode 100644 (file)
index 0000000..9b71708
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/sh
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux target_at_least dm-raid 1 3 0 || skip
+
+aux prepare_vg 5 80
+
+# Extend RAID10 (2-stripes, 2-mirror)
+for deactivate in true false; do
+       lvcreate --type raid10 -m 1 -i 2 -l 2 -n $lv1 $vg
+
+       if $deactivate; then
+               lvchange -an $vg/$lv1
+       fi
+
+       lvresize -l +2 $vg/$lv1
+
+       #check raid_images_contiguous $vg $lv1
+
+       lvremove -ff $vg
+done
+
+# Reduce RAID10 (2-stripes, 2-mirror)
+for deactivate in true false; do
+       lvcreate --type raid10 -m 1 -i 2 -l 4 -n $lv1 $vg
+
+       if $deactivate; then
+               lvchange -an $vg/$lv1
+       fi
+
+       should lvresize -y -l -2 $vg/$lv1
+
+       #check raid_images_contiguous $vg $lv1
+
+       lvremove -ff $vg
+done
diff --git a/test/shell/lvresize-rounding.sh b/test/shell/lvresize-rounding.sh
new file mode 100644 (file)
index 0000000..ad8d9c0
--- /dev/null
@@ -0,0 +1,90 @@
+#!/bin/sh
+# Copyright (C) 2007-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_pvs 3 22
+
+vgcreate -s 32K $vg "$dev1" "$dev2" "$dev3"
+
+lvcreate -l4 -i3 -I64 $vg
+
+lvcreate -l8 -i2 -I64 $vg
+
+lvcreate -l16 $vg
+
+lvcreate -l32 -i3 -I64 -n $lv1 $vg
+
+lvresize -l+64 -i3 -I64 $vg/$lv1
+
+lvresize -l+64 -i3 -I128 $vg/$lv1
+
+#lvcreate -l100%FREE -i3 -I64 --alloc anywhere $vg
+
+dmsetup table
+
+vgcfgbackup -f /tmp/vg $vg
+vgremove -f $vg
+
+# 15 extents
+aux prepare_vg 3 22
+
+# Block some extents
+lvcreate -l4 -i3 $vg
+lvcreate -l1 $vg
+
+lvcreate -l100%FREE -n $lv1 -i3 $vg
+check vg_field $vg vg_free_count 2
+lvremove -f $vg/$lv1
+
+lvcreate -l1 -n $lv1 -i3 $vg
+lvextend -l+100%FREE -i3 $vg/$lv1
+check vg_field $vg vg_free_count 2
+
+lvreduce -f -l50%LV $vg/$lv1
+vgremove -f $vg
+
+
+vgcreate -s 4M $vg "$dev1" "$dev2" "$dev3"
+
+# Expect to play with 15 extents
+check vg_field $vg vg_free_count 15
+
+# Should be rounded to 12 extents
+lvcreate -l10 -n lv -i3 $vg
+check vg_field $vg vg_free_count 3
+
+# Should want 16 extents
+not lvextend -l+4 $vg/lv
+
+# Round up to whole free space
+lvextend -l+100%FREE $vg/lv
+check vg_field $vg vg_free_count 0
+
+# Rounds up and should reduce just by 3 extents
+lvreduce -f -l-4 $vg/lv
+check vg_field $vg vg_free_count 3
+
+# Should round up to 15 extents
+lvextend -f -l+1 $vg/lv
+check vg_field $vg vg_free_count 0
+
+lvreduce -f -l-4 $vg/lv
+check vg_field $vg vg_free_count 3
+
+lvextend -l90%VG $vg/lv
+check vg_field $vg vg_free_count 0
+
+not lvreduce -f -l-10%LV $vg/lv
+check vg_field $vg vg_free_count 0
+
+lvreduce -f -l-20%LV $vg/lv
+check vg_field $vg vg_free_count 3
diff --git a/test/shell/lvresize-usage.sh b/test/shell/lvresize-usage.sh
new file mode 100644 (file)
index 0000000..51ef221
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh
+# Copyright (C) 2007-2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_vg 2
+
+lvcreate -L 10M -n lv -i2 $vg
+lvresize -l +4 $vg/lv
+lvremove -ff $vg
+
+lvcreate -L 64M -n $lv -i2 $vg
+not lvresize -v -l +4 xxx/$lv
diff --git a/test/shell/mdata-strings.sh b/test/shell/mdata-strings.sh
new file mode 100644 (file)
index 0000000..16e9360
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Copyright (C) 2008-2011 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# 'Test for proper escaping of strings in metadata (bz431474)'
+
+. lib/test
+
+aux prepare_devs 2
+aux lvmconf 'devices/global_filter = [ "a|.*LVMTEST.*dev/mapper/.*pv[0-9_]*$|", "r|.*|" ]'
+
+# for udev impossible to create
+pv_ugly="__\"!@#\$%^&*,()|@||'\\\"__pv1"
+
+# 'set up temp files, loopback devices'
+name=$(basename "$dev1")
+dmsetup rename "$name" "$PREFIX$pv_ugly"
+dev1=$(dirname "$dev1")/"$PREFIX$pv_ugly"
+
+dm_table | grep -F "$pv_ugly"
+
+# 'pvcreate, vgcreate on filename with backslashed chars'
+created="$dev1"
+# when used with real udev without fallback, it will fail here
+pvcreate "$dev1" || created="$dev2"
+pvdisplay | should grep -F "$pv_ugly"
+should check pv_field "$dev1" pv_name "$dev1"
+vgcreate $vg "$created"
+# 'no parse errors and VG really exists'
+vgs $vg 2>err
+not grep "Parse error" err
diff --git a/test/shell/metadata-balance.sh b/test/shell/metadata-balance.sh
new file mode 100644 (file)
index 0000000..88ac114
--- /dev/null
@@ -0,0 +1,232 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_devs 6
+
+echo Make sure we can ignore / un-ignore mdas on a per-PV basis
+for pv_in_vg in 1 0; do
+for mdacp in 1 2; do
+       pvcreate --metadatacopies $mdacp "$dev1" "$dev2"
+        pvcreate --metadatacopies 0 "$dev3"
+       if [ $pv_in_vg = 1 ]; then
+               vgcreate -c n $vg "$dev1" "$dev2" "$dev3"
+       fi
+       pvchange --metadataignore y "$dev1"
+       check pv_field "$dev1" pv_mda_count $mdacp
+       check pv_field "$dev1" pv_mda_used_count 0
+       check pv_field "$dev2" pv_mda_count $mdacp
+       check pv_field "$dev2" pv_mda_used_count $mdacp
+       if [ $pv_in_vg = 1 ]; then
+               check vg_field $vg vg_mda_count $(($mdacp * 2))
+               check vg_field $vg vg_mda_used_count $mdacp
+               check vg_field $vg vg_mda_copies unmanaged
+       fi
+       pvchange --metadataignore n "$dev1"
+       check pv_field "$dev1" pv_mda_count $mdacp
+       check pv_field "$dev1" pv_mda_used_count $mdacp
+       if [ $pv_in_vg = 1 ]; then
+               check vg_field $vg vg_mda_count $(($mdacp * 2))
+               check vg_field $vg vg_mda_used_count $(($mdacp * 2))
+               check vg_field $vg vg_mda_copies unmanaged
+               vgremove -f $vg
+       fi
+done
+done
+
+# Check if a PV has unignored (used) mdas, and if so, ignore
+pvignore_ () {
+       pv_mda_used_count=$(get pv_field "$1" pv_mda_used_count)
+       if [ $pv_mda_used_count -ne 0 ]; then
+           pvchange --metadataignore y $1
+       fi
+}
+
+# Check if a PV has ignored mdas, and if so, unignore (make used)
+pvunignore_ () {
+       pv_mda_count=$(get pv_field "$1" pv_mda_count)
+       pv_mda_used_count=$(get pv_field "$1" pv_mda_used_count)
+       if [ $pv_mda_count -gt $pv_mda_used_count ]; then
+           pvchange --metadataignore n $1
+       fi
+}
+
+echo Test of vgmetadatacopies with vgcreate and vgchange
+for mdacp in 1 2; do
+       pvcreate --metadatacopies $mdacp "$dev1" "$dev2" "$dev4" "$dev5"
+       check pv_field "$dev1" pv_mda_used_count $mdacp
+       check pv_field "$dev2" pv_mda_used_count $mdacp
+       check pv_field "$dev4" pv_mda_used_count $mdacp
+       check pv_field "$dev5" pv_mda_used_count $mdacp
+       pvcreate --metadatacopies 0 "$dev3"
+       vgcreate -c n $vg "$dev1" "$dev2" "$dev3"
+       check vg_field $vg vg_mda_copies unmanaged
+       echo ensure both --vgmetadatacopies and --metadatacopies accepted
+       vgchange --metadatacopies $(($mdacp * 1)) $vg
+       echo --vgmetadatacopies is persistent on disk
+       echo --vgmetadatacopies affects underlying pv mda ignore
+       check vg_field $vg vg_mda_copies $(($mdacp * 1))
+       check vg_field $vg vg_mda_used_count $(($mdacp * 1))
+       vgchange --vgmetadatacopies $(($mdacp * 2)) $vg
+       check vg_field $vg vg_mda_copies $(($mdacp * 2))
+       check vg_field $vg vg_mda_used_count $(($mdacp * 2))
+       echo allow setting metadatacopies larger than number of PVs
+       vgchange --vgmetadatacopies $(($mdacp * 5)) $vg
+       check vg_field $vg vg_mda_copies $(($mdacp * 5))
+       check vg_field $vg vg_mda_used_count $(($mdacp * 2))
+       echo setting to 0 disables automatic balancing
+       vgchange --vgmetadatacopies unmanaged $vg
+       check vg_field $vg vg_mda_copies unmanaged
+       vgremove -f $vg
+       echo vgcreate succeeds even when creating a VG w/all ignored mdas
+       pvchange --metadataignore y "$dev1" "$dev2"
+       check pv_field "$dev1" pv_mda_count $mdacp
+       check pv_field "$dev2" pv_mda_used_count 0
+       vgcreate -c n $vg "$dev1" "$dev2"
+       check vg_field $vg vg_mda_copies unmanaged
+       vgremove -f $vg
+       echo vgcreate succeeds with a specific number of metadata copies
+       vgcreate -c n --vgmetadatacopies $(($mdacp * 2)) $vg "$dev1" "$dev2"
+       check vg_field $vg vg_mda_copies $(($mdacp * 2))
+       vgremove -f $vg
+       vgcreate -c n --vgmetadatacopies $(($mdacp * 1)) $vg "$dev1" "$dev2"
+       check vg_field $vg vg_mda_copies $(($mdacp * 1))
+       vgremove -f $vg
+       echo vgcreate succeeds with a larger value than total metadatacopies
+       vgcreate -c n --vgmetadatacopies $(($mdacp * 5)) $vg "$dev1" "$dev2"
+       check vg_field $vg vg_mda_copies $(($mdacp * 5))
+       vgremove -f $vg
+       echo vgcreate succeeds with --vgmetadatacopies unmanaged
+       vgcreate -c n --vgmetadatacopies unmanaged $vg "$dev1" "$dev2"
+       check vg_field $vg vg_mda_copies unmanaged
+       vgremove -f $vg
+       pvunignore_ "$dev1"
+       pvunignore_ "$dev2"
+       pvunignore_ "$dev4"
+       pvunignore_ "$dev5"
+       echo vgcreate succeds with small value of --metadatacopies, ignores mdas
+       vgcreate -c n --vgmetadatacopies 1 $vg "$dev1" "$dev2" "$dev4" "$dev5"
+       check vg_field $vg vg_mda_copies 1
+       check vg_field $vg vg_mda_count $(($mdacp * 4))
+       check vg_field $vg vg_mda_used_count 1
+       echo Setting a larger value should trigger non-ignore of mdas
+       vgchange --metadatacopies 3 $vg
+       check vg_field $vg vg_mda_copies 3
+       check vg_field $vg vg_mda_used_count 3
+       echo Setting all should trigger unignore of all mdas
+       vgchange --vgmetadatacopies all $vg
+       check vg_field $vg vg_mda_count $(($mdacp * 4))
+       check vg_field $vg vg_mda_copies unmanaged
+       check vg_field $vg vg_mda_used_count $(($mdacp * 4))
+       echo --vgmetadatacopies 0 should be unmanaged for vgchange and vgcreate
+       vgchange --vgmetadatacopies 0 $vg
+       check vg_field $vg vg_mda_copies unmanaged
+       vgremove -f $vg
+       vgcreate -c n --vgmetadatacopies 0 $vg "$dev1" "$dev2" "$dev4" "$dev5"
+       check vg_field $vg vg_mda_copies unmanaged
+       vgremove -f $vg
+done
+
+echo Test vgextend / vgreduce with vgmetadatacopies
+for mdacp in 1 2; do
+       pvcreate --metadatacopies $mdacp "$dev1" "$dev2" "$dev4" "$dev5"
+       pvcreate --metadatacopies 0 "$dev3"
+       echo Set a large value of vgmetadatacopies
+       vgcreate -c n --vgmetadatacopies $(($mdacp * 5)) $vg "$dev1" "$dev2" "$dev3"
+       check vg_field $vg vg_mda_copies $(($mdacp * 5))
+       echo Ignore mdas on devices to be used for vgextend
+       echo Large value of vgetadatacopies should automatically un-ignore mdas
+       pvchange --metadataignore y "$dev4" "$dev5"
+       check pv_field "$dev4" pv_mda_used_count 0
+       vgextend $vg "$dev4" "$dev5"
+       check pv_field "$dev4" pv_mda_used_count $mdacp
+       check pv_field "$dev5" pv_mda_used_count $mdacp
+       vgremove -f $vg
+       echo Set a small value of vgmetadatacopies
+       vgcreate -c n --vgmetadatacopies $(($mdacp * 1)) $vg "$dev1" "$dev2" "$dev3"
+       check vg_field $vg vg_mda_copies $(($mdacp * 1))
+       echo Ignore mdas on devices to be used for vgextend
+       echo Small value of vgetadatacopies should leave mdas as ignored
+       pvchange --metadataignore y "$dev4" "$dev5"
+       check pv_field "$dev4" pv_mda_used_count 0
+       vgextend $vg "$dev4" "$dev5"
+       check pv_field "$dev4" pv_mda_used_count 0
+       check pv_field "$dev5" pv_mda_used_count 0
+       echo vgreduce of ignored pv w/mda should not trigger any change to ignore bits
+       vgreduce $vg "$dev4"
+       check pv_field "$dev4" pv_mda_used_count 0
+       check pv_field "$dev5" pv_mda_used_count 0
+       echo vgreduce of un-ignored pv w/mda should trigger un-ignore on an mda
+       vgreduce $vg "$dev1" "$dev2" "$dev3"
+       check pv_field "$dev5" pv_mda_used_count $mdacp
+       check vg_field $vg vg_mda_copies $(($mdacp * 1))
+       pvunignore_ "$dev1"
+       pvunignore_ "$dev2"
+       echo setting vgmetadatacopies to unmanaged should allow vgextend to add w/out balancing
+       vgchange --vgmetadatacopies unmanaged $vg
+       vgextend $vg "$dev1" "$dev2"
+       check vg_field $vg vg_mda_copies unmanaged
+       check vg_field $vg vg_mda_count $(($mdacp * 3))
+       check vg_field $vg vg_mda_used_count $((mdacp * 3))
+       check pv_field "$dev1" pv_mda_used_count $mdacp
+       check pv_field "$dev2" pv_mda_used_count $mdacp
+       vgremove -f $vg
+done
+
+echo Test special situations, vgsplit, vgmerge, etc
+for mdacp in 1 2; do
+       pvcreate --metadatacopies $mdacp "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+       vgcreate -c n --vgmetadatacopies 2 $vg1 "$dev1" "$dev2" "$dev3"
+       vgcreate -c n --vgmetadatacopies $(($mdacp * 1)) $vg2 "$dev4" "$dev5"
+       echo vgsplit/vgmerge preserves value of metadata copies
+       check vg_field $vg1 vg_mda_copies 2
+       check vg_field $vg2 vg_mda_copies $(($mdacp * 1))
+       vgsplit $vg1 $vg2 "$dev1"
+       check vg_field $vg2 vg_mda_copies $(($mdacp * 1))
+       vgmerge $vg1 $vg2
+       check vg_field $vg1 vg_mda_copies 2
+       check vg_field $vg1 vg_mda_count $(($mdacp * 5))
+       echo vgsplit into new vg sets proper value of vgmetadatacopies
+       vgsplit --vgmetadatacopies $(($mdacp * 2)) $vg1 $vg2 "$dev1" "$dev2"
+       check vg_field $vg2 vg_mda_copies $(($mdacp * 2))
+       echo vgchange fails if given both vgmetadatacopies and metadatacopies
+       not vgchange --vgmetadatacopies 5 --metadatacopies 7 $vg2
+       vgremove -f $vg1 $vg2
+done
+
+echo Test combination of --vgmetadatacopies and pvchange --metadataignore
+for mdacp in 1 2; do
+       pvcreate --metadatacopies $mdacp "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+       vgcreate -c n --vgmetadatacopies $(($mdacp * 1)) $vg1 "$dev1" "$dev2"
+       check vg_field $vg1 vg_mda_copies $(($mdacp * 1))
+       check vg_field $vg1 vg_mda_used_count $(($mdacp * 1))
+       pvignore_ "$dev3"
+       echo Ensure vgextend of PVs with ignored MDAs does not add to vg_mda_used_count
+       vgextend $vg1 "$dev3"
+       check vg_field $vg1 vg_mda_used_count $(($mdacp * 1))
+       echo Using pvchange to unignore should update vg_mda_used_count
+       pvchange -f --metadataignore n "$dev3"
+       check pv_field "$dev3" pv_mda_used_count $mdacp
+       check vg_field $vg1 vg_mda_used_count $(($mdacp * 2))
+       echo Set unmanaged on the vg should keep ignore bits the same during vgextend
+       vgchange --vgmetadatacopies unmanaged $vg1
+       check vg_field $vg1 vg_mda_used_count $(($mdacp * 2))
+       pvunignore_ "$dev4"
+       vgextend $vg1 "$dev4"
+       check pv_field "$dev4" pv_mda_used_count $mdacp
+       check vg_field $vg1 vg_mda_used_count $(($mdacp * 3))
+       echo Using pvchange to ignore should update vg_mda_used_count
+       pvchange -f --metadataignore y "$dev4"
+       check pv_field "$dev4" pv_mda_used_count 0
+       check vg_field $vg1 vg_mda_used_count $(($mdacp * 2))
+       vgremove -f $vg1
+done
diff --git a/test/shell/metadata-dirs.sh b/test/shell/metadata-dirs.sh
new file mode 100644 (file)
index 0000000..852ce35
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/sh
+# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_devs 3
+
+pvcreate --metadatacopies 0 $(cat DEVICES)
+not vgcreate $vg $(cat DEVICES)
+
+aux lvmconf "metadata/dirs = [ \"$TESTDIR/mda\" ]"
+
+vgcreate $vg "$dev1"
+check vg_field $vg vg_mda_count 1
+vgremove -ff $vg
+
+vgcreate $vg $(cat DEVICES)
+check vg_field $vg vg_mda_count 1
+vgremove -ff $vg
+
+pvcreate --metadatacopies 1 --metadataignore y "$dev1"
+vgcreate $vg $(cat DEVICES)
+check vg_field $vg vg_mda_count 2
+vgremove -ff $vg
+
+pvcreate --metadatacopies 1 --metadataignore n "$dev1"
+vgcreate $vg $(cat DEVICES)
+check vg_field $vg vg_mda_count 2
+vgremove -ff $vg
+
+pvcreate --metadatacopies 0 "$dev1"
+aux lvmconf "metadata/dirs = [ \"$TESTDIR/mda\", \"$TESTDIR/mda2\" ]"
+vgcreate $vg $(cat DEVICES)
+check vg_field $vg vg_mda_count 2
+vgremove -ff $vg
diff --git a/test/shell/metadata.sh b/test/shell/metadata.sh
new file mode 100644 (file)
index 0000000..a9f8640
--- /dev/null
@@ -0,0 +1,76 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_devs 5
+
+pvcreate "$dev1"
+pvcreate --metadatacopies 0 "$dev2"
+pvcreate --metadatacopies 0 "$dev3"
+pvcreate "$dev4"
+pvcreate --metadatacopies 0 "$dev5"
+
+vgcreate -c n $vg $(cat DEVICES)
+lvcreate -n $lv -l 1 -i5 -I256 $vg
+
+pvchange -x n "$dev1"
+pvchange -x y "$dev1"
+vgchange -a n $vg
+pvchange --uuid "$dev1"
+pvchange --uuid "$dev2"
+vgremove -f $vg
+
+# check that PVs without metadata don't cause too many full device rescans (bz452606)
+for mdacp in 1 0; do
+       pvcreate --metadatacopies $mdacp $(cat DEVICES)
+       pvcreate "$dev1"
+       vgcreate -c n $vg $(cat DEVICES)
+       lvcreate -n $lv1 -l 2 -i5 -I256 $vg
+       lvcreate -n $lv2 -m2 -l 2  $vg
+       lvchange -an $vg/$lv1 $vg/$lv2
+       vgchange -ay $vg
+       lvchange -an $vg/$lv1 $vg/$lv2
+       vgremove -f $vg
+done
+not grep "Cached VG .* incorrect PV list" out0
+
+# some M1 metadata tests
+pvcreate -M1 "$dev1" "$dev2" "$dev3"
+pv3_uuid=$(get pv_field "$dev3" pv_uuid)
+vgcreate -M1 -c n $vg "$dev1" "$dev2" "$dev3"
+pvchange --uuid "$dev1"
+
+# verify pe_start of all M1 PVs
+pv_align="128.00k"
+check pv_field "$dev1" pe_start $pv_align
+check pv_field "$dev2" pe_start $pv_align
+check pv_field "$dev3" pe_start $pv_align
+
+pvs --units k -o name,pe_start,vg_mda_size,vg_name $(cat DEVICES)
+
+# upgrade from v1 to v2 metadata
+vgconvert -M2 $vg
+
+# verify pe_start of all M2 PVs
+check pv_field "$dev1" pe_start $pv_align
+check pv_field "$dev2" pe_start $pv_align
+check pv_field "$dev3" pe_start $pv_align
+
+pvs --units k -o name,pe_start,vg_mda_size,vg_name $(cat DEVICES)
+
+# create backup and then restore $dev3
+vgcfgbackup -f $TESTDIR/bak-%s $vg
+pvcreate -ff -y --restorefile $TESTDIR/bak-$vg --uuid $pv3_uuid "$dev3"
+vgcfgrestore -f $TESTDIR/bak-$vg $vg
+
+# verify pe_start of $dev3
+check pv_field "$dev3" pe_start $pv_align
diff --git a/test/shell/mirror-names.sh b/test/shell/mirror-names.sh
new file mode 100644 (file)
index 0000000..d6c67ee
--- /dev/null
@@ -0,0 +1,132 @@
+#!/bin/sh
+# Copyright (C) 2007-2012 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2007-2008 NEC Corporation
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+test_description="check namings of mirrored LV"
+
+. lib/test
+
+# ---------------------------------------------------------------------
+# Utilities
+
+lv_devices_() {
+       local d
+       local lv=$1
+       shift
+       local devices=$@
+       local devs=$(get lv_field $lv devices -a | sed 's/([0-9]*)//g; s/ //g; s/,/ /g')
+
+       for d in $devs; do
+               (echo $devices | grep $d) || return 1
+               devices=$(echo $devices | sed "s/$d//")
+       done
+
+       test -z "$(echo $devices | sed 's/ //g')"
+}
+
+lv_mirror_log_() {
+       test $(get lv_field $1 mirror_log) = $2
+}
+
+lv_convert_lv_() {
+       get lv_field $1 convert_lv
+}
+
+# ---------------------------------------------------------------------
+# Common environment setup/cleanup for each sub testcases
+
+check_and_cleanup_lvs_() {
+       lvs -a -o+devices $vg
+       lvremove -ff $vg
+       (dm_table | not grep $vg) || \
+               die "ERROR: lvremove did leave some some mappings in DM behind!"
+}
+
+# ---------------------------------------------------------------------
+# Initialize PVs and VGs
+
+aux prepare_vg 5 80
+
+check_and_cleanup_lvs_
+
+# ---------------------------------------------------------------------
+# basic
+
+#COMM "init: lvcreate"
+
+#COMM "mirror images are ${lv1}_mimage_x"
+lvcreate -l2 -m1 -n $lv1 $vg
+lv_devices_ $vg/$lv1 ${lv1}_mimage_0 ${lv1}_mimage_1
+
+#COMM "mirror log is ${lv1}_mlog"
+lv_mirror_log_ $vg/$lv1 ${lv1}_mlog
+
+# "cleanup"
+check_and_cleanup_lvs_
+
+#COMM "mirror with name longer than 22 characters (bz221322)"
+name="LVwithanamelogerthan22characters_butidontwonttocounthem"
+lvcreate -m1 -l2 -n $name $vg
+lvs $vg/$name
+check_and_cleanup_lvs_
+
+# ---------------------------------------------------------------------
+# lvrename
+
+#COMM "init: lvrename"
+
+#COMM "renamed mirror names: $lv1 to $lv2"
+lvcreate -l2 -m1 -n $lv1 $vg
+lvrename $vg/$lv1 $vg/$lv2
+lv_devices_ $vg/$lv2 ${lv2}_mimage_0 ${lv2}_mimage_1
+lv_mirror_log_ $vg/$lv2 ${lv2}_mlog
+
+#COMM "cleanup"
+check_and_cleanup_lvs_
+
+# ---------------------------------------------------------------------
+# lvconvert
+
+#COMM "init: lvconvert"
+
+#COMM "converting mirror names is ${lv1}_mimagetmp_2"
+lvcreate -l2 -m1 -n $lv1 $vg
+lvconvert -m+1 -i+40 -b $vg/$lv1
+convlv=$(lv_convert_lv_ $vg/$lv1)
+test $convlv = ${lv1}_mimagetmp_2
+lv_devices_ $vg/$lv1 $convlv ${lv1}_mimage_2
+lv_devices_ $vg/$convlv ${lv1}_mimage_0 ${lv1}_mimage_1
+lv_mirror_log_ $vg/$convlv ${lv1}_mlog
+
+#COMM "mirror log name after re-adding is ${lv1}_mlog" \
+lvconvert --mirrorlog core $vg/$lv1
+lvconvert --mirrorlog disk $vg/$lv1
+convlv=$(lv_convert_lv_ $vg/$lv1)
+lv_devices_ $vg/$lv1 $convlv ${lv1}_mimage_2
+lv_devices_ $vg/$convlv ${lv1}_mimage_0 ${lv1}_mimage_1
+lv_mirror_log_ $vg/$convlv ${lv1}_mlog
+
+#COMM "renamed converting mirror names: $lv1 to $lv2" \
+lvrename $vg/$lv1 $vg/$lv2
+convlv=$(lv_convert_lv_ $vg/$lv2)
+lv_devices_ $vg/$lv2 $convlv ${lv2}_mimage_2
+lv_devices_ $vg/$convlv ${lv2}_mimage_0 ${lv2}_mimage_1
+lv_mirror_log_ $vg/$convlv ${lv2}_mlog
+
+#COMM "cleanup"
+check_and_cleanup_lvs_
+
+# Temporary mirror log should have "_mlogtmp_<n>" suffix
+# but currently lvconvert doesn't have an option to add the log.
+# If such feature is added in future, a test for that should
+# be added.
+
+# ---------------------------------------------------------------------
diff --git a/test/shell/mirror-vgreduce-removemissing.sh b/test/shell/mirror-vgreduce-removemissing.sh
new file mode 100644 (file)
index 0000000..232c2be
--- /dev/null
@@ -0,0 +1,415 @@
+#!/bin/sh
+# Copyright (C) 2008-2012 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2007 NEC Corporation
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+test_description="ensure that 'vgreduce --removemissing' works on mirrored LV"
+
+. lib/test
+
+lv_is_on_ ()
+{
+       local lv=$vg/$1
+       shift
+       local pvs=$@
+
+       echo "Check if $lv is exactly on PVs $pvs"
+       rm -f out1 out2
+       echo $pvs | sed 's/ /\n/g' | sort | uniq > out1
+
+       lvs -a -o+devices $lv
+       get lv_devices $lv | sed 's/ /\n/g' | sort | uniq > out2 || true
+
+       diff --ignore-blank-lines out1 out2
+}
+
+mimages_are_on_ ()
+{
+       local lv=$1
+       shift
+       local pvs=$@
+       local mimages
+       local i
+
+       echo "Check if mirror images of $lv are on PVs $pvs"
+       rm -f out1 out2
+       echo $pvs | sed 's/ /\n/g' | sort | uniq > out1
+       lvs --noheadings -a -o lv_name $vg > lvs_log
+       mimages=$(grep "${lv}_mimage_" lvs_log | \
+               sed 's/\[//g; s/\]//g' || true)
+
+       for i in $mimages; do
+               echo "Checking $vg/$i"
+               lvs -a -o+devices $vg/$i
+               lvs -a -odevices --noheadings $vg/$i > lvs_log
+               sed 's/([^)]*)//g; s/ //g; s/,/ /g' lvs_log | sort | uniq >> out2 || true
+       done
+
+       diff --ignore-blank-lines out1 out2
+}
+
+mirrorlog_is_on_()
+{
+       local lv=${1}_mlog
+       shift
+       lv_is_on_ $lv "$@"
+}
+
+lv_is_linear_()
+{
+       echo "Check if $1 is linear LV (i.e. not a mirror)"
+       get lv_field $vg/$1 "stripes,attr" | grep "^1 -" >/dev/null
+}
+
+rest_pvs_()
+{
+       local index=$1
+       local num=$2
+       local rem=
+       local n
+
+       for n in $(seq 1 $(($index - 1))) $(seq $(($index + 1)) $num); do
+               eval local dev=$\dev$n
+               rem="$rem $dev"
+       done
+
+       echo "$rem"
+}
+
+# ---------------------------------------------------------------------
+# Initialize PVs and VGs
+
+aux prepare_vg 5
+
+# ---------------------------------------------------------------------
+# Common environment setup/cleanup for each sub testcases
+
+prepare_lvs_()
+{
+       lvremove -ff $vg
+       (dm_table | not grep $vg) || \
+               die "ERROR: lvremove did leave some some mappings in DM behind!"
+}
+
+check_and_cleanup_lvs_()
+{
+       lvs -a -o+devices $vg
+       prepare_lvs_
+}
+
+recover_vg_()
+{
+       aux enable_dev "$@"
+       pvcreate -ff "$@"
+       vgextend $vg "$@"
+       check_and_cleanup_lvs_
+}
+
+#COMM "check environment setup/cleanup"
+prepare_lvs_
+check_and_cleanup_lvs_
+
+# ---------------------------------------------------------------------
+# one of mirror images has failed
+
+#COMM "basic: fail the 2nd mirror image of 2-way mirrored LV"
+prepare_lvs_
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0
+lvchange -an $vg/$lv1
+mimages_are_on_ $lv1 $dev1 $dev2
+mirrorlog_is_on_ $lv1 $dev3
+aux disable_dev "$dev2"
+vgreduce --removemissing --force $vg
+lv_is_linear_ $lv1
+lv_is_on_ $lv1 "$dev1"
+
+# "cleanup"
+recover_vg_ "$dev2"
+
+# ---------------------------------------------------------------------
+# LV has 3 images in flat,
+# 1 out of 3 images fails
+
+#COMM test_3way_mirror_fail_1_ <PV# to fail>
+test_3way_mirror_fail_1_()
+{
+       local index=$1
+
+       lvcreate -l2 -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev3" "$dev4":0
+       lvchange -an $vg/$lv1
+       mimages_are_on_ $lv1 "$dev1" "$dev2" "$dev3"
+       mirrorlog_is_on_ $lv1 "$dev4"
+       eval aux disable_dev \$dev$index
+       vgreduce --removemissing --force $vg
+       lvs -a -o+devices $vg
+       mimages_are_on_ $lv1 $(rest_pvs_ $index 3)
+       mirrorlog_is_on_ $lv1 "$dev4"
+}
+
+for n in $(seq 1 3); do
+       #COMM fail mirror image $(($n - 1)) of 3-way mirrored LV"
+       prepare_lvs_
+       test_3way_mirror_fail_1_ $n
+       eval recover_vg_ \$dev$n
+done
+
+# ---------------------------------------------------------------------
+# LV has 3 images in flat,
+# 2 out of 3 images fail
+
+#COMM test_3way_mirror_fail_2_ <PV# NOT to fail>
+test_3way_mirror_fail_2_()
+{
+       local index=$1
+
+       lvcreate -l2 -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev3" "$dev4":0
+       lvchange -an $vg/$lv1
+       mimages_are_on_ $lv1 "$dev1" "$dev2" "$dev3"
+       mirrorlog_is_on_ $lv1 "$dev4"
+       rest_pvs_ $index 3
+       aux disable_dev $(rest_pvs_ $index 3)
+       vgreduce --force --removemissing $vg
+       lvs -a -o+devices $vg
+       lv_is_linear_ $lv1
+       eval lv_is_on_ $lv1 \$dev$n
+}
+
+for n in $(seq 1 3); do
+       #COMM fail mirror images other than mirror image $(($n - 1)) of 3-way mirrored LV
+       prepare_lvs_
+       test_3way_mirror_fail_2_ $n
+       recover_vg_ $(rest_pvs_ $n 3)
+done
+
+# ---------------------------------------------------------------------
+# LV has 4 images, 1 of them is in the temporary mirror for syncing.
+# 1 out of 4 images fails
+
+#COMM test_3way_mirror_plus_1_fail_1_ <PV# to fail>
+test_3way_mirror_plus_1_fail_1_()
+{
+       local index=$1
+
+       lvcreate -l2 -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev3" "$dev5":0
+       lvchange -an $vg/$lv1
+       lvconvert -m+1 $vg/$lv1 "$dev4"
+       check mirror_images_on $vg $lv1 "$dev1" "$dev2" "$dev3" "$dev4"
+       check mirror_log_on $vg $lv1 "$dev5"
+       eval aux disable_dev \$dev$index
+        lvs -a -o +devices
+       vgreduce --removemissing --force $vg
+       lvs -a -o+devices # $vg
+       check mirror_images_on $vg $lv1 "$dev5" # $(rest_pvs_ $index 4)
+       check mirror_log_on $vg $lv1 "$dev5"
+}
+
+for n in $(seq 1 4); do
+       #COMM "fail mirror image $(($n - 1)) of 4-way (1 converting) mirrored LV"
+       prepare_lvs_
+       test_3way_mirror_plus_1_fail_1_ $n
+       eval recover_vg_ \$dev$n
+done
+
+# ---------------------------------------------------------------------
+# LV has 4 images, 1 of them is in the temporary mirror for syncing.
+# 3 out of 4 images fail
+
+#COMM test_3way_mirror_plus_1_fail_3_ <PV# NOT to fail>
+test_3way_mirror_plus_1_fail_3_()
+{
+       local index=$1
+
+       lvcreate -l2 -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev3" "$dev5":0
+       lvchange -an $vg/$lv1
+       lvconvert -m+1 $vg/$lv1 "$dev4"
+       check mirror_images_on $vg $lv1 "$dev1" "$dev2" "$dev3" "$dev4"
+       check mirror_log_on $vg $lv1 "$dev5"
+       lvs -a -o+devices $vg
+       aux disable_dev $(rest_pvs_ $index 4)
+       vgreduce --removemissing --force $vg
+       lvs -a -o+devices $vg
+       eval local dev=\$dev$n
+       check linear $vg $lv1
+        check lv_on $vg $lv1 $dev
+}
+
+for n in $(seq 1 4); do
+       #COMM "fail mirror images other than mirror image $(($n - 1)) of 4-way (1 converting) mirrored LV"
+       prepare_lvs_
+       test_3way_mirror_plus_1_fail_3_ $n
+       recover_vg_ $(rest_pvs_ $n 4)
+done
+
+# ---------------------------------------------------------------------
+# LV has 4 images, 2 of them are in the temporary mirror for syncing.
+# 1 out of 4 images fail
+
+# test_2way_mirror_plus_2_fail_1_ <PV# to fail>
+test_2way_mirror_plus_2_fail_1_()
+{
+       local index=$1
+
+       lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0
+       lvchange -an $vg/$lv1
+       lvconvert -m+2 $vg/$lv1 "$dev3" "$dev4"
+       mimages_are_on_ $lv1 "$dev1" "$dev2" "$dev3" "$dev4"
+       mirrorlog_is_on_ $lv1 "$dev5"
+       eval aux disable_dev \$dev$n
+       vgreduce --removemissing --force $vg
+       lvs -a -o+devices $vg
+       mimages_are_on_ $lv1 $(rest_pvs_ $index 4)
+       mirrorlog_is_on_ $lv1 "$dev5"
+}
+
+for n in $(seq 1 4); do
+       #COMM "fail mirror image $(($n - 1)) of 4-way (2 converting) mirrored LV"
+       prepare_lvs_
+       test_2way_mirror_plus_2_fail_1_ $n
+       eval recover_vg_ \$dev$n
+done
+
+# ---------------------------------------------------------------------
+# LV has 4 images, 2 of them are in the temporary mirror for syncing.
+# 3 out of 4 images fail
+
+# test_2way_mirror_plus_2_fail_3_ <PV# NOT to fail>
+test_2way_mirror_plus_2_fail_3_()
+{
+       local index=$1
+
+       lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0
+       lvchange -an $vg/$lv1
+       lvconvert -m+2 $vg/$lv1 "$dev3" "$dev4"
+       mimages_are_on_ $lv1 "$dev1" "$dev2" "$dev3" "$dev4"
+       mirrorlog_is_on_ $lv1 "$dev5"
+       aux disable_dev $(rest_pvs_ $index 4)
+       vgreduce --removemissing --force $vg
+       lvs -a -o+devices $vg
+       eval local dev=\$dev$n
+       mimages_are_on_ $lv1 $dev || lv_is_on_ $lv1 $dev
+       not mirrorlog_is_on_ $lv1 "$dev5"
+}
+
+for n in $(seq 1 4); do
+       #COMM "fail mirror images other than mirror image $(($n - 1)) of 4-way (2 converting) mirrored LV"
+       prepare_lvs_
+       test_2way_mirror_plus_2_fail_3_ $n
+       recover_vg_ $(rest_pvs_ $n 4)
+done
+
+# ---------------------------------------------------------------------
+# log device is gone (flat mirror and stacked mirror)
+
+#COMM "fail mirror log of 2-way mirrored LV"
+prepare_lvs_
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0
+lvchange -an $vg/$lv1
+mimages_are_on_ $lv1 "$dev1" "$dev2"
+mirrorlog_is_on_ $lv1 "$dev5"
+aux disable_dev "$dev5"
+vgreduce --removemissing --force $vg
+mimages_are_on_ $lv1 "$dev1" "$dev2"
+not mirrorlog_is_on_ $lv1 "$dev5"
+recover_vg_ "$dev5"
+
+#COMM "fail mirror log of 3-way (1 converting) mirrored LV"
+prepare_lvs_
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0
+lvchange -an $vg/$lv1
+lvconvert -m+1 $vg/$lv1 "$dev3"
+mimages_are_on_ $lv1 "$dev1" "$dev2" "$dev3"
+mirrorlog_is_on_ $lv1 "$dev5"
+aux disable_dev "$dev5"
+vgreduce --removemissing --force $vg
+mimages_are_on_ $lv1 "$dev1" "$dev2" "$dev3"
+not mirrorlog_is_on_ $lv1 "$dev5"
+recover_vg_ "$dev5"
+
+# ---------------------------------------------------------------------
+# all images are gone (flat mirror and stacked mirror)
+
+#COMM "fail all mirror images of 2-way mirrored LV"
+prepare_lvs_
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0
+lvchange -an $vg/$lv1
+mimages_are_on_ $lv1 "$dev1" "$dev2"
+mirrorlog_is_on_ $lv1 "$dev5"
+aux disable_dev "$dev1" "$dev2"
+vgreduce --removemissing --force $vg
+not lvs $vg/$lv1
+recover_vg_ "$dev1" "$dev2"
+
+#COMM "fail all mirror images of 3-way (1 converting) mirrored LV"
+prepare_lvs_
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0
+lvchange -an $vg/$lv1
+lvconvert -m+1 $vg/$lv1 "$dev3"
+mimages_are_on_ $lv1 "$dev1" "$dev2" "$dev3"
+mirrorlog_is_on_ $lv1 "$dev5"
+aux disable_dev "$dev1" "$dev2" "$dev3"
+vgreduce --removemissing --force $vg
+not lvs $vg/$lv1
+recover_vg_ "$dev1" "$dev2" "$dev3"
+
+# ---------------------------------------------------------------------
+# Multiple LVs
+
+#COMM "fail a mirror image of one of mirrored LV"
+prepare_lvs_
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0
+lvchange -an $vg/$lv1
+lvcreate -l2 -m1 -n $lv2 $vg "$dev3" "$dev4" "$dev5":1
+lvchange -an $vg/$lv2
+mimages_are_on_ $lv1 "$dev1" "$dev2"
+mimages_are_on_ $lv2 "$dev3" "$dev4"
+mirrorlog_is_on_ $lv1 "$dev5"
+mirrorlog_is_on_ $lv2 "$dev5"
+aux disable_dev "$dev2"
+vgreduce --removemissing --force $vg
+mimages_are_on_ $lv2 "$dev3" "$dev4"
+mirrorlog_is_on_ $lv2 "$dev5"
+lv_is_linear_ $lv1
+lv_is_on_ $lv1 "$dev1"
+recover_vg_ "$dev2"
+
+#COMM "fail mirror images, one for each mirrored LV"
+prepare_lvs_
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0
+lvchange -an $vg/$lv1
+lvcreate -l2 -m1 -n $lv2 $vg "$dev3" "$dev4" "$dev5":1
+lvchange -an $vg/$lv2
+mimages_are_on_ $lv1 "$dev1" "$dev2"
+mimages_are_on_ $lv2 "$dev3" "$dev4"
+mirrorlog_is_on_ $lv1 "$dev5"
+mirrorlog_is_on_ $lv2 "$dev5"
+aux disable_dev "$dev2"
+aux disable_dev "$dev4"
+vgreduce --removemissing --force $vg
+lv_is_linear_ $lv1
+lv_is_on_ $lv1 "$dev1"
+lv_is_linear_ $lv2
+lv_is_on_ $lv2 "$dev3"
+recover_vg_ "$dev2" "$dev4"
+
+# ---------------------------------------------------------------------
+# no failure
+
+#COMM "no failures"
+prepare_lvs_
+lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0
+lvchange -an $vg/$lv1
+mimages_are_on_ $lv1 "$dev1" "$dev2"
+mirrorlog_is_on_ $lv1 "$dev5"
+vgreduce --removemissing --force $vg
+mimages_are_on_ $lv1 "$dev1" "$dev2"
+mirrorlog_is_on_ $lv1 "$dev5"
+check_and_cleanup_lvs_
+
+# ---------------------------------------------------------------------
diff --git a/test/shell/name-mangling.sh b/test/shell/name-mangling.sh
new file mode 100644 (file)
index 0000000..5b92e60
--- /dev/null
@@ -0,0 +1,231 @@
+#!/bin/sh
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+name_prefix=$RANDOM
+
+CHARACTER_WHITELIST="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#+-.:=@_"
+FAIL_MIXED_STR="contains mixed mangled and unmangled characters"
+FAIL_MULTI_STR="seems to be mangled more than once"
+FAIL_BLACK_STR="should be mangled but it contains blacklisted characters"
+CORRECT_FORM_STR="name already in correct form"
+RENAMING_STR="renaming to"
+
+function create_dm_dev()
+{
+       local mode=$1
+       local name=$2;
+
+       if [ $mode = "none" ]; then
+               # there's no mangling done - we must use --verifyudev here in
+               # case we're testing with udev so we have the nodes in place,
+               # udev would not create them - it can't handle unmangled names
+               verify_udev="--verifyudev"
+       else
+               verify_udev=""
+       fi
+
+       dmsetup create "${name_prefix}$name" $verify_udev --manglename $mode --table "0 1 zero"
+}
+
+function remove_dm_dev()
+{
+       local mode=$1
+       local name=$2
+
+       if [ $mode = "none" ]; then
+               verify_udev="--verifyudev"
+       else
+               verify_udev=""
+       fi
+
+       dmsetup remove $verify_udev --manglename $mode "${name_prefix}$name"
+}
+
+function check_create_and_remove()
+{
+       local mode=$1
+       local input_name=$2
+       local dm_name=$3
+       local r=0
+
+       if [ $mode = "none" ]; then
+               verify_udev="--verifyudev"
+       else
+               verify_udev=""
+       fi
+
+       dmsetup create "${name_prefix}$input_name" $verify_udev --manglename $mode --table "0 1 zero" 2>err && \
+       test -b "$DM_DEV_DIR/mapper/${name_prefix}$dm_name" && \
+       dmsetup remove "${name_prefix}$input_name" $verify_udev --manglename $mode || r=1
+
+       if [ $dm_name = "FAIL_MIXED" ]; then
+               r=0
+               grep "$FAILED_MIXED_STR" err || r=1
+       elif [ $dm_name = "FAIL_MULTI" ]; then
+               r=0
+               grep "$FAILED_MULTI_STR" err || r=1
+       elif [ $dm_name = "FAIL_BLACK" ]; then
+               r=0
+               grep "$FAILED_BLACK_STR" err || r=1
+       fi
+
+       return $r
+}
+
+function check_dm_field()
+{
+       local mode=$1
+       local dm_name="$2"
+       local field=$3
+       local expected="$4"
+
+       value=$(dmsetup info --rows --noheadings --manglename $mode -c -o $field "${DM_DEV_DIR}/mapper/${name_prefix}$dm_name" 2> err || true)
+
+       if [ "$expected" = "FAIL_MIXED" ]; then
+               grep "$FAIL_MIXED_STR" err
+       elif [ "$expected" = "FAIL_MULTI" ]; then
+               grep "$FAIL_MULTI_STR" err
+       elif [ "$expected" = "FAIL_BLACK" ]; then
+               grep "$FAIL_BLACK_STR" err
+       else
+               test "$value" = "${name_prefix}$expected"
+       fi
+}
+
+function check_expected_names()
+{
+       local mode=$1
+       local dm_name="$2"
+       local r=0
+
+       create_dm_dev none "$dm_name"
+
+       test -b "$DM_DEV_DIR/mapper/${name_prefix}$dm_name" && \
+       check_dm_field none "$dm_name" name "$dm_name" && \
+       check_dm_field $mode "$dm_name" name "$3" && \
+       check_dm_field $mode "$dm_name" mangled_name "$4" && \
+       check_dm_field $mode "$dm_name" unmangled_name "$5" || r=1
+
+       remove_dm_dev none "$dm_name"
+
+       return $r
+}
+
+function check_mangle_cmd()
+{
+       local mode=$1
+       local dm_name="$2"
+       local expected="$3"
+       local rename_expected=0
+       local r=0
+
+       create_dm_dev none "$dm_name"
+
+       dmsetup mangle --manglename $mode "${name_prefix}$dm_name" 1>out 2>err || true;
+
+       if [ "$expected" = "OK" ]; then
+               grep "$CORRECT_FORM_STR" out || r=1
+       elif [ "$expected" = "FAIL_MIXED" ]; then
+               grep "$FAIL_MIXED_STR" err || r=1
+       elif [ "$expected" = "FAIL_MULTI" ]; then
+               grep "$FAIL_MULTI_STR" err || r=1
+       else
+               rename_expected=1
+               grep -F "$RENAMING_STR ${name_prefix}$expected" out || r=1
+       fi
+
+       if [ $r = 0 -a $rename_expected = 1 ]; then
+               # successfuly renamed to expected name
+               remove_dm_dev none "$expected"
+       elif [ $r = 1 ]; then
+               # failed to rename to expected or renamed when it should not - find the new name
+               new_name=$(sed -e "s/.*: $RENAMING_STR //g" out)
+               # try to remove any of the form - falling back to less probable error scenario
+               dmsetup remove --verifyudev --manglename none "$new_name" || \
+               remove_dm_dev none "$dm_name" || remove_dm_dev none "$expected"
+       else
+               # successfuly done nothing
+               remove_dm_dev none "$dm_name"
+       fi
+
+       return $r
+}
+
+# check dmsetup can process path where the last component is not equal dm name (rhbz #797322)
+r=0
+create_dm_dev auto "abc"
+ln -s ${DM_DEV_DIR}/mapper/${name_prefix}abc ${DM_DEV_DIR}/${name_prefix}xyz
+dmsetup status ${DM_DEV_DIR}/${name_prefix}xyz || r=1
+remove_dm_dev auto "abc"
+if [ r = 1 ]; then
+       exit 1
+fi
+
+### ALL WHITELISTED CHARACTERS ###
+# none of these should be mangled in any mode
+name="$CHARACTER_WHITELIST"
+for mode in auto hex none; do
+       check_expected_names $mode "$name" "$name" "$name" "$name"
+       check_mangle_cmd $mode "$name" "OK"
+done
+
+
+#### NONE MANGLING MODE ###
+check_create_and_remove none 'a b' 'a b'
+check_create_and_remove none 'a\x20b' 'a\x20b'
+check_create_and_remove none 'a b\x20c' 'a b\x20c'
+check_create_and_remove none 'a\x5cx20b' 'a\x5cx20b'
+
+check_expected_names none 'a b' 'a b' 'a\x20b' 'a b'
+check_expected_names none 'a\x20b' 'a\x20b' 'a\x20b' 'a b'
+check_expected_names none 'a b\x20c' 'a b\x20c' 'FAIL_MIXED' 'a b c'
+check_expected_names none 'a\x5cx20b' 'a\x5cx20b' 'a\x5cx20b' 'a\x20b'
+
+check_mangle_cmd none 'a b' 'OK'
+check_mangle_cmd none 'a\x20b' 'a b'
+check_mangle_cmd none 'a b\x20c' 'a b c'
+check_mangle_cmd none 'a\x5cx20b' 'a\x20b'
+
+
+### AUTO MANGLING MODE ###
+check_create_and_remove auto 'a b' 'a\x20b'
+check_create_and_remove auto 'a\x20b' 'a\x20b'
+check_create_and_remove auto 'a b\x20c' 'FAIL_MIXED'
+check_create_and_remove auto 'a\x5cx20b' 'FAIL_MULTI'
+
+check_expected_names auto 'a b' 'FAIL_BLACK' 'FAIL_BLACK' 'FAIL_BLACK'
+check_expected_names auto 'a\x20b' 'a b' 'a\x20b' 'a b'
+check_expected_names auto 'a b\x20c' 'FAIL_BLACK' 'FAIL_BLACK' 'FAIL_BLACK'
+check_expected_names auto 'a\x5cx20b' 'FAIL_MULTI' 'FAIL_MULTI' 'FAIL_MULTI'
+
+check_mangle_cmd auto 'a b' 'a\x20b'
+check_mangle_cmd auto 'a\x20b' 'OK'
+check_mangle_cmd auto 'a b\x20c' 'FAIL_MIXED'
+check_mangle_cmd auto 'a\x5cx20b' 'FAIL_MULTI'
+
+
+### HEX MANGLING MODE ###
+check_create_and_remove hex 'a b' 'a\x20b'
+check_create_and_remove hex 'a\x20b' 'a\x5cx20b'
+check_create_and_remove hex 'a b\x20c' 'a\x20b\x5cx20c'
+check_create_and_remove hex 'a\x5cx20b' 'a\x5cx5cx20b'
+
+check_expected_names hex 'a b' 'FAIL_BLACK' 'FAIL_BLACK' 'FAIL_BLACK'
+check_expected_names hex 'a\x20b' 'a b' 'a\x20b' 'a b'
+check_expected_names hex 'a b\x20c' 'FAIL_BLACK' 'FAIL_BLACK' 'FAIL_BLACK'
+check_expected_names hex 'a\x5cx20b' 'a\x20b' 'a\x5cx20b' 'a\x20b'
+
+check_mangle_cmd hex 'a b' 'a\x20b'
+check_mangle_cmd hex 'a\x20b' 'OK'
+check_mangle_cmd hex 'a b\x20c' 'FAIL_MIXED'
+check_mangle_cmd hex 'a\x5cx20b' 'OK'
diff --git a/test/shell/nomda-missing.sh b/test/shell/nomda-missing.sh
new file mode 100644 (file)
index 0000000..2cf759e
--- /dev/null
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_devs 4
+pvcreate "$dev1" "$dev2"
+pvcreate --metadatacopies 0 "$dev3" "$dev4"
+vgcreate -c n $vg "$dev1" "$dev2" "$dev3" "$dev4"
+
+lvcreate -l1 -n linear1 $vg "$dev1"
+lvcreate -l1 -n linear2 $vg "$dev2"
+lvcreate -l2 -n linear12 $vg "$dev1":4 "$dev2":4
+
+lvcreate -l1 -n origin1 $vg "$dev1"
+lvcreate -s $vg/origin1 -l1 -n s_napshot2 "$dev2"
+
+lvcreate -l1 -m1 -n mirror12 --mirrorlog core $vg "$dev1" "$dev2"
+lvcreate -l1 -m1 -n mirror123 $vg "$dev1" "$dev2" "$dev3"
+
+vgchange -a n $vg
+aux disable_dev "$dev1"
+not vgchange -a y $vg
+not vgck $vg
+
+check inactive $vg linear1
+check active $vg linear2
+check inactive $vg origin1
+check inactive $vg s_napshot2
+check inactive $vg linear12
+check inactive $vg mirror12
+check inactive $vg mirror123
+
+vgchange -a n $vg
+aux enable_dev "$dev1"
+aux disable_dev "$dev2"
+not vgchange -a y $vg
+not vgck $vg
+
+check active $vg linear1
+check inactive $vg linear2
+check inactive $vg linear12
+check inactive $vg origin1
+check inactive $vg s_napshot2
+check inactive $vg mirror12
+check inactive $vg mirror123
+
+vgchange -a n $vg
+aux enable_dev "$dev2"
+aux disable_dev "$dev3"
+not vgchange -a y $vg
+not vgck $vg
+
+check active $vg origin1
+check active $vg s_napshot2
+check active $vg linear1
+check active $vg linear2
+check active $vg linear12
+check inactive $vg mirror123
+check active $vg mirror12
+
+vgchange -a n $vg
+aux enable_dev "$dev3"
+aux disable_dev "$dev4"
+vgchange -a y $vg
+not vgck $vg
+
+check active $vg origin1
+check active $vg s_napshot2
+check active $vg linear1
+check active $vg linear2
+check active $vg linear12
+check active $vg mirror12
+check active $vg mirror123
diff --git a/test/shell/pool-labels.sh b/test/shell/pool-labels.sh
new file mode 100644 (file)
index 0000000..9d3fa03
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/sh
+# Copyright (C) 2007 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+env printf "" || skip # skip if printf is not available
+
+# create the old GFS pool labeled linear devices
+create_pool_label_()
+{
+  # FIXME
+  # echo -e is bashism, dash builtin sh doesn't do \xNN in printf either
+  # printf comes from coreutils, and is probably not posix either
+  env printf "\x01\x16\x70\x06\x5f\xcf\xff\xb9\xf8\x24\x8apool1" | dd of="$2" bs=5 seek=1 conv=notrunc
+  env printf "\x04\x01\x03\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x0$1\x68\x01\x16\x70\x00\x00\x00\x00\x00\x06\x5f\xd0" | dd of=$2 bs=273 seek=1 conv=notrunc
+  aux notify_lvmetad "$2"
+}
+
+
+aux prepare_devs 2
+
+create_pool_label_ 0 "$dev1"
+create_pool_label_ 1 "$dev2"
+
+# check that pvcreate fails without -ff on the pool device
+not pvcreate "$dev1"
+
+# check that vgdisplay and pvcreate -ff works with the pool device
+vgdisplay --config 'global { locking_type = 0 }'
+aux disable_dev "$dev2"
+# FIXME! since pool1 cannot be opened, vgdisplay gives error... should we say
+# "not" there instead, checking that it indeed does fail?
+vgdisplay --config 'global { locking_type = 0 }' || true
+pvcreate -ff -y "$dev1"
diff --git a/test/shell/pv-duplicate.sh b/test/shell/pv-duplicate.sh
new file mode 100644 (file)
index 0000000..6a22cd1
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/sh
+# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# 'Exercise duplicate metadata diagnostics'
+
+. lib/test
+
+aux prepare_devs 3
+
+vgcreate -c n --metadatasize 128k $vg1 "$dev1"
+
+# copy mda
+dd if="$dev1" of="$dev2" bs=256K count=1
+dd if="$dev1" of="$dev3" bs=256K count=1
+
+pvs "$dev1"
+vgs $vg1
diff --git a/test/shell/pv-min-size.sh b/test/shell/pv-min-size.sh
new file mode 100644 (file)
index 0000000..59250cf
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+# use small default size  - 512KB
+aux lvmconf 'devices/pv_min_size = 512'
+
+aux prepare_pvs 1 8
+
+check pv_field "$dev1" pv_name "$dev1"
+
+# increase min size beyond created PV size 10MB
+aux lvmconf 'devices/pv_min_size = 10240'
+
+# and test device is not visible
+not check pv_field "$dev1" pv_name "$dev1"
+
+# set too low value errornous value
+aux lvmconf 'devices/pv_min_size = -100'
+
+# check the incorrect value is printed
+pvs "$dev1" 2>&1 | grep -- -100
diff --git a/test/shell/pv-range-overflow.sh b/test/shell/pv-range-overflow.sh
new file mode 100644 (file)
index 0000000..0f353dd
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/sh
+# Copyright (C) 2008-2011 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# 'Ensure that pvmove diagnoses PE-range values 2^32 and larger.'
+
+. lib/test
+
+aux prepare_vg 2
+
+lvcreate -L4 -n"$lv" $vg
+
+# Test for the bogus diagnostic reported in BZ 284771
+# http://bugzilla.redhat.com/284771.
+# 'run pvmove with an unrecognized LV name to show bad diagnostic'
+not pvmove -v -nbogus "$dev1" "$dev2" 2> err
+grep "Logical volume bogus not found." err
+
+# With lvm-2.02.28 and earlier, on a system with 64-bit "long int",
+# the PE range parsing code would accept values up to 2^64-1, but would
+# silently truncate them to int32_t.  I.e., $dev1:$(echo 2^32|bc) would be
+# treated just like $dev1:0.
+# 'run the offending pvmove command'
+not pvmove -v -n$lv "$dev1":4294967296 "$dev2"
+
diff --git a/test/shell/pvchange-usage.sh b/test/shell/pvchange-usage.sh
new file mode 100644 (file)
index 0000000..d5a2ebb
--- /dev/null
@@ -0,0 +1,65 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# 'Test pvchange option values'
+
+. lib/test
+
+aux prepare_devs 4
+
+for mda in 0 1 2
+do
+# "setup pv with metadatacopies = $mda"
+       pvcreate "$dev4"
+       pvcreate --metadatacopies $mda "$dev1"
+       vgcreate $vg1 "$dev1" "$dev4"
+
+# "pvchange adds/dels tag to pvs with metadatacopies = $mda "
+       pvchange "$dev1" --addtag test$mda
+       check pv_field "$dev1" pv_tags test$mda
+       pvchange "$dev1" --deltag test$mda
+       check pv_field "$dev1" pv_tags ""
+
+# "vgchange disable/enable allocation for pvs with metadatacopies = $mda (bz452982)"
+       pvchange "$dev1" -x n
+       check pv_field "$dev1" pv_attr  ---
+       pvchange "$dev1" -x y
+       check pv_field "$dev1" pv_attr  a--
+
+# 'remove pv'
+       vgremove $vg1
+       pvremove "$dev1" "$dev4"
+done
+
+# "pvchange uuid"
+pvcreate --metadatacopies 0 "$dev1"
+pvcreate --metadatacopies 2 "$dev2"
+vgcreate $vg1 "$dev1" "$dev2"
+pvchange -u "$dev1"
+pvchange -u "$dev2"
+check pvlv_counts $vg1 2 0 0
+pvchange -u --all
+check pvlv_counts $vg1 2 0 0
+
+# "pvchange rejects uuid change under an active lv"
+lvcreate -l 16 -i 2 -n $lv --alloc anywhere $vg1
+check pvlv_counts $vg1 2 1 0
+not pvchange -u "$dev1"
+lvchange -an $vg1/$lv
+pvchange -u "$dev1"
+
+# "cleanup"
+lvremove -f $vg1/$lv
+vgremove $vg1
+
+# "pvchange reject --addtag to lvm1 pv"
+pvcreate -M1 "$dev1"
+not pvchange "$dev1" --addtag test
diff --git a/test/shell/pvcreate-metadata0.sh b/test/shell/pvcreate-metadata0.sh
new file mode 100644 (file)
index 0000000..9154e75
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+#
+# Testcase for bugzilla #450651
+# also checks that vgremove properly removes all lv devices in the right order
+#
+# 'Test pvcreate without metadata on all pvs'
+
+. lib/test
+
+aux prepare_devs 2 128
+
+#lv_snap=$lv2
+pvcreate "$dev1"
+pvcreate --metadatacopies 0 "$dev2"
+
+# "check lv snapshot"
+vgcreate -c n $vg "$dev1" "$dev2"
+lvcreate -n $lv -l 60%FREE $vg
+lvcreate -s -n $lv2 -l 10%FREE $vg/$lv
+pvdisplay
+lvdisplay
+vgremove -f $vg
diff --git a/test/shell/pvcreate-operation-md.sh b/test/shell/pvcreate-operation-md.sh
new file mode 100644 (file)
index 0000000..9bdc4a1
--- /dev/null
@@ -0,0 +1,149 @@
+#!/bin/sh
+# Copyright (C) 2009 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+# skip this test if mdadm or sfdisk (or others) aren't available
+which mdadm || skip
+which sfdisk || skip
+which perl || skip
+which awk || skip
+which cut || skip
+
+test -f /proc/mdstat && grep -q raid0 /proc/mdstat || \
+       modprobe raid0 || skip
+
+aux lvmconf 'devices/md_component_detection = 1'
+aux lvmconf 'devices/filter = [ "a|/dev/md.*|", "a/dev\/mapper\/.*$/", "r/.*/" ]'
+aux prepare_devs 2
+
+# Have MD use a non-standard name to avoid colliding with an existing MD device
+# - mdadm >= 3.0 requires that non-standard device names be in /dev/md/
+# - newer mdadm _completely_ defers to udev to create the associated device node
+mdadm_maj=$(mdadm --version 2>&1 | perl -pi -e 's|.* v(\d+).*|\1|')
+[ $mdadm_maj -ge 3 ] && \
+    mddev=/dev/md/md_lvm_test0 || \
+    mddev=/dev/md_lvm_test0
+
+cleanup_md() {
+    # sleeps offer hack to defeat: 'md: md127 still in use'
+    # see: https://bugzilla.redhat.com/show_bug.cgi?id=509908#c25
+    aux udev_wait
+    mdadm --stop "$mddev" || true
+    aux udev_wait
+    if [ -b "$mddev" ]; then
+        # mdadm doesn't always cleanup the device node
+       sleep 2
+       rm -f "$mddev"
+    fi
+}
+
+cleanup_md_and_teardown() {
+    cleanup_md
+    aux teardown
+}
+
+# create 2 disk MD raid0 array (stripe_width=128K)
+test -b "$mddev" && skip
+mdadm --create --metadata=1.0 "$mddev" --auto=md --level 0 --raid-devices=2 --chunk 64 "$dev1" "$dev2"
+trap 'cleanup_md_and_teardown' EXIT # cleanup this MD device at the end of the test
+test -b "$mddev" || skip
+
+# Test alignment of PV on MD without any MD-aware or topology-aware detection
+# - should treat $mddev just like any other block device
+pv_align="1.00m"
+pvcreate --metadatasize 128k \
+    --config 'devices {md_chunk_alignment=0 data_alignment_detection=0 data_alignment_offset_detection=0}' \
+    "$mddev"
+check pv_field "$mddev" pe_start $pv_align
+
+# Test md_chunk_alignment independent of topology-aware detection
+pv_align="1.00m"
+pvcreate --metadatasize 128k \
+    --config 'devices {data_alignment_detection=0 data_alignment_offset_detection=0}' \
+    "$mddev"
+check pv_field "$mddev" pe_start $pv_align
+
+
+# Test newer topology-aware alignment detection
+# - first added to 2.6.31 but not "reliable" until 2.6.33
+if kernel_at_least 2 6 33 ; then
+    pv_align="1.00m"
+    # optimal_io_size=131072, minimum_io_size=65536
+    pvcreate --metadatasize 128k \
+       --config 'devices { md_chunk_alignment=0 }' "$mddev"
+    check pv_field "$mddev" pe_start $pv_align
+fi
+
+# partition MD array directly, depends on blkext in Linux >= 2.6.28
+if kernel_at_least 2 6 28 ; then
+    # create one partition
+    sfdisk "$mddev" <<EOF
+,,83
+EOF
+    # make sure partition on MD is _not_ removed
+    # - tests partition -> parent lookup via sysfs paths
+    not pvcreate --metadatasize 128k "$mddev"
+
+    # verify alignment_offset is accounted for in pe_start
+    # - topology infrastructure is available in Linux >= 2.6.31
+    # - also tests partition -> parent lookup via sysfs paths
+
+    # Oh joy: need to lookup /sys/block/md127 rather than /sys/block/md_lvm_test0
+    mddev_maj_min=$(ls -lL "$mddev" | awk '{ print $5 $6 }' | perl -pi -e 's|,|:|')
+    mddev_p_sysfs_name=$(echo /sys/dev/block/${mddev_maj_min}/*p1)
+    base_mddev_p=`basename $mddev_p_sysfs_name`
+    mddev_p=/dev/${base_mddev_p}
+
+    # in case the system is running without devtmpfs /dev
+    # wait here for created device node on tmpfs
+    aux udev_wait "$mddev_p"
+    test -b "$mddev_p" || skip
+
+    # Checking for 'alignment_offset' in sysfs implies Linux >= 2.6.31
+    # but reliable alignment_offset support requires kernel.org Linux >= 2.6.33
+    sysfs_alignment_offset=/sys/dev/block/${mddev_maj_min}/${base_mddev_p}/alignment_offset
+    [ -f $sysfs_alignment_offset ] && kernel_at_least 2 6 33 && \
+       alignment_offset=`cat $sysfs_alignment_offset` || \
+       alignment_offset=0
+
+    if [ $alignment_offset -gt 0 ]; then
+        # default alignment is 1M, add alignment_offset
+       pv_align=$((1048576+$alignment_offset))B
+       pvcreate --metadatasize 128k "$mddev_p"
+       check pv_field "$mddev_p" pe_start $pv_align --units b
+       pvremove "$mddev_p"
+    fi
+fi
+
+# Test newer topology-aware alignment detection w/ --dataalignment override
+if kernel_at_least 2 6 33 ; then
+    cleanup_md
+    pvcreate -f "$dev1"
+    pvcreate -f "$dev2"
+
+    # create 2 disk MD raid0 array (stripe_width=2M)
+    test -b "$mddev" && skip
+    mdadm --create --metadata=1.0 "$mddev" --auto=md --level 0 --raid-devices=2 --chunk 1024 "$dev1" "$dev2"
+    test -b "$mddev" || skip
+
+    # optimal_io_size=2097152, minimum_io_size=1048576
+    pv_align="2.00m"
+    pvcreate --metadatasize 128k \
+       --config 'devices { md_chunk_alignment=0 }' "$mddev"
+    check pv_field "$mddev" pe_start $pv_align
+
+    # now verify pe_start alignment override using --dataalignment
+    pv_align="192.00k"
+    pvcreate --dataalignment 64k --metadatasize 128k \
+       --config 'devices { md_chunk_alignment=0 }' "$mddev"
+    check pv_field "$mddev" pe_start $pv_align
+fi
diff --git a/test/shell/pvcreate-operation.sh b/test/shell/pvcreate-operation.sh
new file mode 100644 (file)
index 0000000..55fff4e
--- /dev/null
@@ -0,0 +1,130 @@
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux lvmconf 'devices/md_component_detection = 1'
+
+aux prepare_devs 4
+
+for mdatype in 1 2
+do
+# pvcreate (lvm$mdatype) refuses to overwrite an mounted filesystem (bz168330)
+       test ! -d mnt && mkdir mnt
+       if mke2fs "$dev1"; then
+               mount "$dev1" mnt
+               not pvcreate -M$mdatype "$dev1" 2>err
+               grep "Can't open "$dev1" exclusively.  Mounted filesystem?" err
+               umount "$dev1"
+       fi
+
+# pvcreate (lvm$mdatype) succeeds when run repeatedly (pv not in a vg) (bz178216)
+    pvcreate -M$mdatype "$dev1"
+    pvcreate -M$mdatype "$dev1"
+    pvremove -f "$dev1"
+
+# pvcreate (lvm$mdatype) fails when PV belongs to VG
+#   pvcreate -M$mdatype "$dev1"
+    vgcreate -M$mdatype $vg1 "$dev1"
+    not pvcreate -M$mdatype "$dev1"
+
+    vgremove -f $vg1
+    pvremove -f "$dev1"
+
+# pvcreate (lvm$mdatype) fails when PV1 does and PV2 does not belong to VG
+    pvcreate -M$mdatype "$dev1"
+    pvcreate -M$mdatype "$dev2"
+    vgcreate -M$mdatype $vg1 "$dev1"
+
+# pvcreate a second time on $dev2 and $dev1
+    not pvcreate -M$mdatype "$dev2" "$dev1"
+
+    vgremove -f $vg1
+    pvremove -f "$dev2" "$dev1"
+
+# NOTE: Force pvcreate after test completion to ensure clean device
+#test_expect_success
+#  "pvcreate (lvm$mdatype) fails on md component device"
+#  'mdadm -C -l raid0 -n 2 /dev/md0 "$dev1" "$dev2" &&
+#   pvcreate -M$mdatype "$dev1";
+#   status=$?; echo status=$status; test $status != 0 &&
+#   mdadm --stop /dev/md0 &&
+#   pvcreate -ff -y -M$mdatype "$dev1" "$dev2" &&
+#   pvremove -f "$dev1" "$dev2"'
+done
+
+# pvcreate (lvm2) fails without -ff when PV with metadatacopies=0 belongs to VG
+pvcreate --metadatacopies 0 "$dev1"
+pvcreate --metadatacopies 1 "$dev2"
+vgcreate $vg1 "$dev1" "$dev2"
+not pvcreate "$dev1"
+vgremove -f $vg1
+pvremove -f "$dev2" "$dev1"
+
+# pvcreate (lvm2) succeeds with -ff when PV with metadatacopies=0 belongs to VG
+pvcreate --metadatacopies 0 "$dev1"
+pvcreate --metadatacopies 1 "$dev2"
+vgcreate $vg1 "$dev1" "$dev2"
+pvcreate -ff -y "$dev1"
+vgreduce --removemissing $vg1
+vgremove -ff $vg1
+pvremove -f "$dev2" "$dev1"
+
+for i in 0 1 2 3
+do
+# pvcreate (lvm2) succeeds writing LVM label at sector $i
+    pvcreate --labelsector $i "$dev1"
+    dd if="$dev1" bs=512 skip=$i count=1 2>/dev/null | strings | grep LABELONE >/dev/null
+    pvremove -f "$dev1"
+done
+
+# pvcreate (lvm2) fails writing LVM label at sector 4
+not pvcreate --labelsector 4 "$dev1"
+
+backupfile=$PREFIX.mybackupfile
+uuid1=freddy-fred-fred-fred-fred-fred-freddy
+uuid2=freddy-fred-fred-fred-fred-fred-fredie
+bogusuuid=fred
+
+# pvcreate rejects uuid option with less than 32 characters
+not pvcreate --norestorefile --uuid $bogusuuid "$dev1"
+
+# pvcreate rejects uuid option without restorefile
+not pvcreate --uuid $uuid1 "$dev1"
+
+# pvcreate rejects uuid already in use
+pvcreate --norestorefile --uuid $uuid1 "$dev1"
+not pvcreate --norestorefile --uuid $uuid1 "$dev2"
+
+# pvcreate rejects non-existent file given with restorefile
+not pvcreate --uuid $uuid1 --restorefile $backupfile "$dev1"
+
+# pvcreate rejects restorefile with uuid not found in file
+pvcreate --norestorefile --uuid $uuid1 "$dev1"
+vgcfgbackup -f $backupfile
+not pvcreate --uuid $uuid2 --restorefile $backupfile "$dev2"
+
+# vgcfgrestore of a VG containing a PV with zero PEs (bz #820116)
+# (use case: one PV in a VG used solely to keep metadata)
+size_mb=$(($(blockdev --getsz $dev1) / 2048))
+pvcreate --metadatasize $size_mb $dev1
+vgcreate $vg1 $dev1
+vgcfgbackup -f $backupfile
+vgcfgrestore -f $backupfile $vg1
+vgremove -f $vg1
+pvremove -f $dev1
+
+# pvcreate wipes swap signature when forced
+dd if=/dev/zero of="$dev1" bs=1024 count=64
+mkswap "$dev1"
+blkid -c /dev/null "$dev1" | grep "swap"
+pvcreate -f "$dev1"
+# blkid cannot make up its mind whether not finding anything it knows is a failure or not
+(blkid -c /dev/null "$dev1" || true) | not grep "swap"
diff --git a/test/shell/pvcreate-usage.sh b/test/shell/pvcreate-usage.sh
new file mode 100644 (file)
index 0000000..148802f
--- /dev/null
@@ -0,0 +1,188 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+test_description='Test pvcreate option values'
+PAGESIZE=$(getconf PAGESIZE)
+
+. lib/test
+
+aux prepare_devs 4
+
+#COMM 'pvcreate rejects negative setphysicalvolumesize'
+not pvcreate --setphysicalvolumesize -1024 "$dev1"
+
+#COMM 'pvcreate rejects negative metadatasize'
+not pvcreate --metadatasize -1024 "$dev1"
+
+# x. metadatasize 0, defaults to 255
+# FIXME: unable to check default value, not in reporting cmds
+# should default to 255 according to code
+#   check pv_field pv_mda_size 255 
+#COMM 'pvcreate accepts metadatasize 0'
+pvcreate --metadatasize 0 "$dev1"
+pvremove "$dev1"
+
+#Verify vg_mda_size is smaller pv_mda_size
+pvcreate --metadatasize 512k "$dev1"
+pvcreate --metadatasize 96k "$dev2"
+vgcreate $vg "$dev1" "$dev2"
+check compare_fields vgs $vg vg_mda_size pvs "$dev2" pv_mda_size
+vgremove $vg
+
+# x. metadatasize too large
+# For some reason we allow this, even though there's no room for data?
+##COMM  'pvcreate rejects metadatasize too large' 
+#not pvcreate --metadatasize 100000000000000 "$dev1"
+
+#COMM 'pvcreate rejects metadatacopies < 0'
+not pvcreate --metadatacopies -1 "$dev1"
+
+#COMM 'pvcreate accepts metadatacopies = 0, 1, 2'
+for j in metadatacopies pvmetadatacopies
+do
+pvcreate --$j 0 "$dev1"
+pvcreate --$j 1 "$dev2"
+pvcreate --$j 2 "$dev3"
+check pv_field "$dev1" pv_mda_count 0
+check pv_field "$dev2" pv_mda_count 1
+check pv_field "$dev3" pv_mda_count 2
+pvremove "$dev1" "$dev2" "$dev3"
+done
+
+#COMM 'pvcreate rejects metadatacopies > 2'
+not pvcreate --metadatacopies 3 "$dev1"
+
+#COMM 'pvcreate rejects invalid device'
+not pvcreate "$dev1"bogus
+
+#COMM 'pvcreate rejects labelsector < 0'
+not pvcreate --labelsector -1 "$dev1"
+
+#COMM 'pvcreate rejects labelsector > 1000000000000'
+not pvcreate --labelsector 1000000000000 "$dev1"
+
+# other possibilites based on code inspection (not sure how hard)
+# x. device too small (min of 512 * 1024 KB)
+# x. device filtered out
+# x. unable to open /dev/urandom RDONLY
+# x. device too large (pe_count > UINT32_MAX)
+# x. device read-only
+# x. unable to open device readonly
+# x. BLKGETSIZE64 fails
+# x. set size to value inconsistent with device / PE size
+
+#COMM 'pvcreate basic dataalignment sanity checks'
+not pvcreate --dataalignment -1 "$dev1"
+not pvcreate -M 1 --dataalignment 1 "$dev1"
+not pvcreate --dataalignment 1e "$dev1"
+
+#COMM 'pvcreate always rounded up to page size for start of device'
+#pvcreate --metadatacopies 0 --dataalignment 1 "$dev1"
+# amuse shell experts
+#check pv_field "$dev1" pe_start $(($(getconf PAGESIZE)/1024))".00k"
+
+#COMM 'pvcreate sets data offset directly'
+pvcreate --dataalignment 512k "$dev1"
+check pv_field "$dev1" pe_start "512.00k"
+
+#COMM 'vgcreate/vgremove do not modify data offset of existing PV'
+vgcreate $vg "$dev1"  --config 'devices { data_alignment = 1024 }'
+check pv_field "$dev1" pe_start "512.00k"
+vgremove $vg --config 'devices { data_alignment = 1024 }'
+check pv_field "$dev1" pe_start "512.00k"
+
+#COMM 'pvcreate sets data offset next to mda area'
+pvcreate --metadatasize 100k --dataalignment 100k "$dev1"
+check pv_field "$dev1" pe_start "200.00k"
+
+# metadata area start is aligned according to pagesize
+case "$PAGESIZE" in
+ 65536) pv_align="192.50k" ;;
+ 8192) pv_align="136.50k" ;;
+ *)    pv_align="133.00k" ;;
+esac
+
+pvcreate --metadatasize 128k --dataalignment 3.5k "$dev1"
+check pv_field "$dev1" pe_start $pv_align
+
+pvcreate --metadatasize 128k --metadatacopies 2 --dataalignment 3.5k "$dev1"
+check pv_field "$dev1" pe_start $pv_align
+
+# data area is aligned to 1M by default,
+# data area start is shifted by the specified alignment_offset
+pv_align=1052160B # 1048576 + (7*512)
+pvcreate --metadatasize 128k --dataalignmentoffset 7s "$dev1"
+check pv_field "$dev1" pe_start $pv_align --units b
+
+# 2nd metadata area is created without problems when
+# data area start is shifted by the specified alignment_offset
+pvcreate --metadatasize 128k --metadatacopies 2 --dataalignmentoffset 7s "$dev1"
+check pv_field "$dev1" pv_mda_count 2
+# FIXME: compare start of 2nd mda with and without --dataalignmentoffset
+
+#COMM 'pv with LVM1 compatible data alignment can be convereted'
+#compatible == LVM1_PE_ALIGN == 64k
+pvcreate --dataalignment 256k "$dev1"
+vgcreate -s 1m $vg "$dev1"
+vgconvert -M1 $vg
+vgconvert -M2 $vg
+check pv_field "$dev1" pe_start 256.00k
+vgremove $vg
+
+#COMM 'pv with LVM1 incompatible data alignment cannot be convereted'
+pvcreate --dataalignment 10k "$dev1"
+vgcreate -s 1m $vg "$dev1"
+not vgconvert -M1 $vg
+vgremove $vg
+
+#COMM 'vgcfgrestore allows pe_start=0'
+#basically it produces nonsense, but it tests vgcfgrestore,
+#not that final cfg is usable...
+pvcreate --metadatacopies 0 "$dev1"
+pvcreate "$dev2"
+vgcreate $vg "$dev1" "$dev2"
+vgcfgbackup -f backup.$$ $vg
+sed 's/pe_start = [0-9]*/pe_start = 0/' backup.$$ > backup.$$1
+vgcfgrestore -f backup.$$1 $vg
+check pv_field "$dev1" pe_start "0"
+check pv_field "$dev2" pe_start "0"
+vgremove $vg
+
+echo "test pvcreate --metadataignore"
+for pv_in_vg in 1 0; do
+for mdacp in 1 2; do
+for ignore in y n; do
+       echo "pvcreate --metadataignore has proper mda_count and mda_used_count"
+       pvcreate --metadatacopies $mdacp --metadataignore $ignore "$dev1" "$dev2"
+       check pv_field "$dev1" pv_mda_count "$mdacp"
+       check pv_field "$dev2" pv_mda_count "$mdacp"
+       if [ $ignore = y ]; then
+               check pv_field "$dev1" pv_mda_used_count "0"
+               check pv_field "$dev2" pv_mda_used_count "0"
+       else
+               check pv_field "$dev1" pv_mda_used_count "$mdacp"
+               check pv_field "$dev2" pv_mda_used_count "$mdacp"
+       fi
+       echo "vgcreate has proper vg_mda_count and vg_mda_used_count"
+       if [ $pv_in_vg = 1 ]; then
+               vgcreate -c n $vg "$dev1" "$dev2"
+               check vg_field $vg vg_mda_count "$(($mdacp * 2))"
+               if [ $ignore = y ]; then
+                       check vg_field $vg vg_mda_used_count "1"
+               else
+                       check vg_field $vg vg_mda_used_count "$(($mdacp * 2))"
+               fi
+               check vg_field $vg vg_mda_copies "unmanaged"
+               vgremove $vg
+       fi
+done
+done
+done
diff --git a/test/shell/pvmove-basic.sh b/test/shell/pvmove-basic.sh
new file mode 100644 (file)
index 0000000..e95fc36
--- /dev/null
@@ -0,0 +1,383 @@
+#!/bin/sh
+# Copyright (C) 2008-2012 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2007 NEC Corporation
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+test_description="ensure that pvmove works with basic options"
+
+. lib/test
+
+which mkfs.ext2 || skip
+which md5sum || skip
+
+# ---------------------------------------------------------------------
+# Utilities
+
+lvdev_() {
+  echo "$DM_DEV_DIR/$1/$2"
+}
+
+lv_is_on_() {
+  local lv=$1 #allready vg/lv
+  shift 1
+  lvs -a -odevices --noheadings $lv | sed 's/,/\n/g' > out
+#is on all specified devs
+  for d in $*; do grep "$d(" out; done
+#isn't on any other dev (we are set -e remember)
+  for d in $*; do ! grep -v "$d(" out; done
+  return 0
+}
+
+save_dev_sum_() {
+  mkfs.ext2 $1 > /dev/null && md5sum $1 > md5.$(basename $1)
+}
+
+check_dev_sum_() {
+  md5sum -c md5.$(basename $1)
+}
+
+create_vg_() {
+  vgcreate -c n -s 128k $vg $(cat DEVICES)
+}
+# ---------------------------------------------------------------------
+# Initialize PVs and VGs
+
+#aux prepare_vg 5 30
+aux prepare_pvs 5 5
+create_vg_
+
+# ---------------------------------------------------------------------
+# Common environment setup/cleanup for each sub testcases
+FIRST=""
+
+prepare_lvs_() {
+  lvcreate -l2 -n $lv1 $vg "$dev1"
+    test -z "$FIRST" && lv_is_on_ $vg/$lv1 "$dev1"
+  lvcreate -l9 -i3 -n $lv2 $vg "$dev2" "$dev3" "$dev4"
+    test -z "$FIRST" && lv_is_on_ $vg/$lv2 "$dev2" "$dev3" "$dev4"
+  lvextend -l+2 $vg/$lv1 "$dev2"
+    test -z "$FIRST" && lv_is_on_ $vg/$lv1 "$dev1" "$dev2"
+  lvextend -l+2 $vg/$lv1 "$dev3"
+    test -z "$FIRST" && lv_is_on_ $vg/$lv1 "$dev1" "$dev2" "$dev3"
+  lvextend -l+2 $vg/$lv1 "$dev1"
+    test -z "$FIRST" && lv_is_on_ $vg/$lv1 "$dev1" "$dev2" "$dev3" "$dev1"
+  lvcreate -l1 -n $lv3 $vg "$dev2"
+    test -z "$FIRST" && lv_is_on_ $vg/$lv3 "$dev2"
+  save_dev_sum_ $(lvdev_ $vg $lv1)
+  save_dev_sum_ $(lvdev_ $vg $lv2)
+  save_dev_sum_ $(lvdev_ $vg $lv3)
+  if test -z "$FIRST" ; then
+    get lv_field $vg/$lv1 devices > ${lv1}_devs
+    get lv_field $vg/$lv2 devices > ${lv2}_devs
+    get lv_field $vg/$lv3 devices > ${lv3}_devs
+  fi
+  FIRST=done
+}
+
+lv_not_changed_() {
+  get lv_field $1 devices > out
+  diff $(basename $1)_devs out
+}
+
+check_and_cleanup_lvs_() {
+  lvs -a -o+devices $vg
+  check_dev_sum_ $(lvdev_ $vg $lv1)
+  check_dev_sum_ $(lvdev_ $vg $lv2)
+  check_dev_sum_ $(lvdev_ $vg $lv3)
+  lvs -a -o name $vg > out && ! grep ^pvmove out
+  lvremove -ff $vg
+  (dm_table | not grep $vg) || \
+       die "ERROR: lvremove did leave some some mappings in DM behind!"
+}
+
+#COMM "check environment setup/cleanup"
+prepare_lvs_
+check_and_cleanup_lvs_
+
+# ---------------------------------------------------------------------
+# pvmove tests
+
+# ---
+# filter by LV
+
+#COMM "only specified LV is moved: from pv2 to pv5 only for lv1"
+prepare_lvs_
+pvmove -i1 -n $vg/$lv1 "$dev2" "$dev5"
+lv_is_on_ $vg/$lv1 "$dev1" "$dev5" "$dev3" "$dev1"
+lv_not_changed_ $vg/$lv2
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+# ---
+# segments in a LV
+
+#COMM "the 1st seg of 3-segs LV is moved: from pv1 of lv1 to pv4"
+prepare_lvs_
+pvmove -i0 -n $vg/$lv1 "$dev1" "$dev4"
+lv_is_on_ $vg/$lv1 "$dev4" "$dev2" "$dev3" "$dev4"
+lv_not_changed_ $vg/$lv2
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+#COMM "the 2nd seg of 3-segs LV is moved: from pv2 of lv1 to pv4"
+prepare_lvs_
+pvmove -i0 -n $vg/$lv1 "$dev2" "$dev4"
+lv_is_on_ $vg/$lv1 "$dev1" "$dev4" "$dev3" "$dev1"
+lv_not_changed_ $vg/$lv2
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+#COMM "the 3rd seg of 3-segs LV is moved: from pv3 of lv1 to pv4"
+prepare_lvs_
+pvmove -i0 -n $vg/$lv1 "$dev3" "$dev4"
+lv_is_on_ $vg/$lv1 "$dev1" "$dev2" "$dev4" "$dev1"
+lv_not_changed_ $vg/$lv2
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+# ---
+# multiple LVs matching
+
+#COMM "1 out of 3 LVs is moved: from pv4 to pv5"
+prepare_lvs_
+pvmove -i0 "$dev4" "$dev5"
+lv_not_changed_ $vg/$lv1
+lv_is_on_ $vg/$lv2 "$dev2" "$dev3" "$dev5"
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+#COMM "2 out of 3 LVs are moved: from pv3 to pv5"
+prepare_lvs_
+pvmove -i0 "$dev3" "$dev5"
+lv_is_on_ $vg/$lv1 "$dev1" "$dev2" "$dev5" "$dev1"
+lv_is_on_ $vg/$lv2 "$dev2" "$dev5" "$dev4"
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+#COMM "3 out of 3 LVs are moved: from pv2 to pv5"
+prepare_lvs_
+pvmove -i0 "$dev2" "$dev5"
+lv_is_on_ $vg/$lv1 "$dev1" "$dev5" "$dev3" "$dev1"
+lv_is_on_ $vg/$lv2 "$dev5" "$dev3" "$dev4"
+lv_is_on_ $vg/$lv3 "$dev5"
+check_and_cleanup_lvs_
+
+# ---
+# areas of striping
+
+#COMM "move the 1st stripe: from pv2 of lv2 to pv1"
+prepare_lvs_
+pvmove -i0 -n $vg/$lv2 "$dev2" "$dev1"
+lv_not_changed_ $vg/$lv1
+lv_is_on_ $vg/$lv2 "$dev1" "$dev3" "$dev4"
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+#COMM "move the 2nd stripe: from pv3 of lv2 to pv1"
+prepare_lvs_
+pvmove -i0 -n $vg/$lv2 "$dev3" "$dev1"
+lv_not_changed_ $vg/$lv1
+lv_is_on_ $vg/$lv2 "$dev2" "$dev1" "$dev4"
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+#COMM "move the 3rd stripe: from pv4 of lv2 to pv1"
+prepare_lvs_
+pvmove -i0 -n $vg/$lv2 "$dev4" "$dev1"
+lv_not_changed_ $vg/$lv1
+lv_is_on_ $vg/$lv2 "$dev2" "$dev3" "$dev1"
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+# ---
+# partial segment match (source segment splitted)
+
+#COMM "match to the start of segment:from pv2:0-0 to pv5"
+prepare_lvs_
+pvmove -i0 "$dev2":0-0 "$dev5"
+lv_not_changed_ $vg/$lv1
+lv_is_on_ $vg/$lv2 "$dev5" "$dev2" "$dev3" "$dev4"
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+#COMM "match to the middle of segment: from pv2:1-1 to pv5"
+prepare_lvs_
+pvmove -i0 "$dev2":1-1 "$dev5"
+lv_not_changed_ $vg/$lv1
+lv_is_on_ $vg/$lv2 "$dev2" "$dev5" "$dev2" "$dev3" "$dev4"
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+#COMM "match to the end of segment: from pv2:2-2 to pv5"
+prepare_lvs_
+pvmove -i0 "$dev2":2-2 "$dev5"
+lv_not_changed_ $vg/$lv1
+lv_is_on_ $vg/$lv2 "$dev2" "$dev5" "$dev3" "$dev4"
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+# ---
+# destination segment splitted
+
+#COMM "no destination split: from pv2:0-2 to pv5"
+prepare_lvs_
+pvmove -i0 "$dev2":0-2 "$dev5"
+lv_not_changed_ $vg/$lv1
+lv_is_on_ $vg/$lv2 "$dev5" "$dev3" "$dev4"
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+#COMM "destination split into 2: from pv2:0-2 to pv5:5-5 and pv4:5-6"
+prepare_lvs_
+pvmove -i0 --alloc anywhere "$dev2":0-2 "$dev5":5-5 "$dev4":5-6
+lv_not_changed_ $vg/$lv1
+lv_is_on_ $vg/$lv2 "$dev5" "$dev4" "$dev3" "$dev4"
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+#COMM "destination split into 3: from pv2:0-2 to {pv3,4,5}:5-5"
+prepare_lvs_
+pvmove -i0 --alloc anywhere "$dev2":0-2 "$dev3":5-5 "$dev4":5-5 "$dev5":5-5
+lv_not_changed_ $vg/$lv1
+lv_is_on_ $vg/$lv2 "$dev3" "$dev4" "$dev5" "$dev3" "$dev4"
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+# ---
+# alloc policy (anywhere, contiguous) with both success and failure cases
+
+#COMM "alloc normal on same PV for source and destination: from pv3:0-2 to pv3:5-7"
+prepare_lvs_
+not pvmove -i0 "$dev3":0-2 "$dev3":5-7
+# "(cleanup previous test)"
+lv_not_changed_ $vg/$lv1
+lv_not_changed_ $vg/$lv2
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+#COMM "alloc anywhere on same PV for source and destination: from pv3:0-2 to pv3:5-7"
+prepare_lvs_
+pvmove -i0 --alloc anywhere "$dev3":0-2 "$dev3":5-7
+lv_not_changed_ $vg/$lv1
+lv_is_on_ $vg/$lv2 "$dev2" "$dev3" "$dev4"
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+#COMM "alloc anywhere but better area available: from pv3:0-2 to pv3:5-7 or pv5:5-6,pv4:5-5"
+prepare_lvs_
+pvmove -i0 --alloc anywhere "$dev3":0-2 "$dev3":5-7 "$dev5":5-6 "$dev4":5-5
+lv_not_changed_ $vg/$lv1
+#lv_is_on_ $vg/$lv2 "$dev2" "$dev5" "$dev4" "$dev4"
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+#COMM "alloc contiguous but area not available: from pv2:0-2 to pv5:5-5 and pv4:5-6"
+prepare_lvs_
+not pvmove -i0 --alloc contiguous "$dev2":0-2 "$dev5":5-5 "$dev4":5-6
+# "(cleanup previous test)"
+lv_not_changed_ $vg/$lv1
+lv_not_changed_ $vg/$lv2
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+#COMM "alloc contiguous and contiguous area available: from pv2:0-2 to pv5:0-0,pv5:3-5 and pv4:5-6"
+prepare_lvs_
+pvmove -i0 --alloc contiguous "$dev2":0-2 "$dev5":0-0 "$dev5":3-5 "$dev4":5-6
+lv_not_changed_ $vg/$lv1
+lv_is_on_ $vg/$lv2 "$dev5" "$dev3" "$dev4"
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+# ---
+# multiple segments in a LV
+
+#COMM "multiple source LVs: from pv3 to pv5"
+prepare_lvs_
+pvmove -i0 "$dev3" "$dev5"
+lv_is_on_ $vg/$lv1 "$dev1" "$dev2" "$dev5"
+lv_is_on_ $vg/$lv2 "$dev2" "$dev5" "$dev4"
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+# ---
+# move inactive LV
+
+#COMM "move inactive LV: from pv2 to pv5"
+prepare_lvs_
+lvchange -an $vg/$lv1
+lvchange -an $vg/$lv3
+pvmove -i0 "$dev2" "$dev5"
+lv_is_on_ $vg/$lv1 "$dev1" "$dev5" "$dev3"
+lv_is_on_ $vg/$lv2 "$dev5" "$dev3" "$dev4"
+lv_is_on_ $vg/$lv3 "$dev5"
+check_and_cleanup_lvs_
+
+# ---
+# other failure cases
+
+#COMM "no PEs to move: from pv3 to pv1"
+prepare_lvs_
+pvmove -i0 "$dev3" "$dev1"
+not pvmove -i0 "$dev3" "$dev1"
+# "(cleanup previous test)"
+lv_is_on_ $vg/$lv1 "$dev1" "$dev2" "$dev1"
+lv_is_on_ $vg/$lv2 "$dev2" "$dev1" "$dev4"
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+#COMM "no space available: from pv2:0-0 to pv1:0-0"
+prepare_lvs_
+not pvmove -i0 "$dev2":0-0 "$dev1":0-0
+# "(cleanup previous test)"
+lv_not_changed_ $vg/$lv1
+lv_not_changed_ $vg/$lv2
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+#COMM 'same source and destination: from pv1 to pv1'
+prepare_lvs_
+not pvmove -i0 "$dev1" "$dev1"
+#"(cleanup previous test)"
+lv_not_changed_ $vg/$lv1
+lv_not_changed_ $vg/$lv2
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+#COMM "sum of specified destination PEs is large enough, but it includes source PEs and the free PEs are not enough"
+prepare_lvs_
+not pvmove --alloc anywhere "$dev1":0-2 "$dev1":0-2 "$dev5":0-0 2> err
+#"(cleanup previous test)"
+grep "Insufficient free space" err
+lv_not_changed_ $vg/$lv1
+lv_not_changed_ $vg/$lv2
+lv_not_changed_ $vg/$lv3
+check_and_cleanup_lvs_
+
+# ---------------------------------------------------------------------
+
+#COMM "pvmove abort"
+prepare_lvs_
+pvmove -i100 -b "$dev1" "$dev3"
+pvmove --abort
+check_and_cleanup_lvs_
+
+#COMM "pvmove out of --metadatacopies 0 PV (bz252150)"
+vgremove -ff $vg
+pvcreate $(cat DEVICES)
+pvcreate --metadatacopies 0 "$dev1" "$dev2"
+create_vg_
+lvcreate -l4 -n $lv1 $vg "$dev1"
+pvmove "$dev1"
+
+#COMM "pvmove fails activating mirror, properly restores state before pvmove"
+dmsetup create $vg-pvmove0 --notable
+not pvmove -i 1 "$dev2"
+test $(dmsetup info --noheadings -c -o suspended $vg-$lv1) = "Active"
+dmsetup remove $vg-pvmove0
diff --git a/test/shell/pvremove-usage.sh b/test/shell/pvremove-usage.sh
new file mode 100644 (file)
index 0000000..c6d724b
--- /dev/null
@@ -0,0 +1,68 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_devs 3
+pvcreate "$dev1"
+pvcreate --metadatacopies 0 "$dev2"
+pvcreate --metadatacopies 2 "$dev3"
+pvremove "$dev2"
+
+# failing, but still removing everything what can be removed
+# is somewhat odd as default, what do we have -f for?
+pvs | not grep "$dev2"
+pvcreate  --metadatacopies 0 "$dev2"
+
+# check pvremove refuses to remove pv in a vg
+vgcreate -c n $vg "$dev1" "$dev2"
+not pvremove "$dev2" "$dev3"
+
+for mdacp in 0 1 2; do
+    # check pvremove truly wipes the label (pvscan wont find) (---metadatacopies $mdacp)
+    pvcreate --metadatacopies $mdacp "$dev3"
+    pvremove "$dev3"
+    # try to remove agail - should fail cleanly
+    not pvremove "$dev3"
+    pvscan | not grep "$dev3"
+
+       # bz179473 refuse to wipe non-PV device without -f
+    not pvremove "$dev3"
+    pvremove -f "$dev3"
+
+    # reset setup
+    vgremove -ff $vg
+    pvcreate --metadatacopies $mdacp "$dev1"
+    pvcreate "$dev2"
+    vgcreate $vg "$dev1" "$dev2"
+
+    # pvremove -f fails when pv in a vg (---metadatacopies $mdacp)
+    not pvremove -f "$dev1"
+    pvs "$dev1"
+
+    # pvremove -ff fails without confirmation when pv in a vg (---metadatacopies $mdacp)
+    echo n | not pvremove -ff "$dev1"
+
+    # pvremove -ff succeds with confirmation when pv in a vg (---metadatacopies $mdacp)
+    pvremove -ffy "$dev1"
+    not pvs "$dev1"
+
+    vgreduce --removemissing $vg
+    pvcreate --metadatacopies $mdacp "$dev1"
+    vgextend $vg "$dev1"
+
+    # pvremove -ff -y is sufficient when pv in a vg (---metadatacopies $mdacp)" '
+    pvremove -ff -y "$dev1"
+
+    vgreduce --removemissing $vg
+    pvcreate --metadatacopies $mdacp "$dev1"
+    vgextend $vg "$dev1"
+done
diff --git a/test/shell/read-ahead.sh b/test/shell/read-ahead.sh
new file mode 100644 (file)
index 0000000..8c8f42c
--- /dev/null
@@ -0,0 +1,49 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+#
+# tests basic functionality of read-ahead and ra regressions
+#
+
+test_description='Test read-ahead functionality'
+
+. lib/test
+
+aux prepare_vg 5
+
+#COMM "test various read ahead settings (bz450922)"
+lvcreate -l 100%FREE -i5 -I256 -n $lv $vg
+ra=$(get lv_field $vg/$lv lv_kernel_read_ahead --units s --nosuffix)
+test $(( ( $ra / 5 ) * 5 )) -eq $ra
+not lvchange -r auto $vg/$lv 2>&1 | grep auto
+check lv_field $vg/$lv lv_read_ahead auto
+check lv_field $vg/$lv lv_kernel_read_ahead 5120 --units s --nosuffix
+lvchange -r 640 $vg/$lv
+check lv_field $vg/$lv lv_read_ahead 640 --units s --nosuffix
+lvremove -ff $vg
+
+#COMM "read ahead is properly inherited from underlying PV"
+blockdev --setra 768 "$dev1"
+vgscan
+lvcreate -n $lv -L4m $vg "$dev1"
+test $(blockdev --getra $DM_DEV_DIR/$vg/$lv) -eq 768
+lvremove -ff $vg
+
+# Check default, active/inactive values for read_ahead / kernel_read_ahead
+lvcreate -n $lv -l 50%FREE $vg
+lvchange -an $vg/$lv
+check lv_field $vg/$lv lv_read_ahead auto
+check lv_field $vg/$lv lv_kernel_read_ahead -1
+lvchange -r 512 $vg/$lv
+lvchange -ay $vg/$lv
+check lv_field $vg/$lv lv_read_ahead 256.00k
+check lv_field $vg/$lv lv_kernel_read_ahead 256.00k
+lvremove -ff $vg
diff --git a/test/shell/snapshot-autoumount-dmeventd.sh b/test/shell/snapshot-autoumount-dmeventd.sh
new file mode 100644 (file)
index 0000000..3b4b711
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/bash
+# Copyright (C) 2010-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# no automatic extensions please
+
+. lib/test
+
+which mkfs.ext2 || skip
+
+aux lvmconf "activation/snapshot_autoextend_percent = 0" \
+            "activation/snapshot_autoextend_threshold = 100"
+
+aux prepare_dmeventd
+aux prepare_vg 2
+mntdir="${PREFIX}mnt"
+
+lvcreate -l 8 -n base $vg
+mkfs.ext2 "$DM_DEV_DIR/$vg/base"
+
+lvcreate -s -l 4 -n snap $vg/base
+lvchange --monitor y $vg/snap
+
+mkdir "$mntdir"
+mount "$DM_DEV_DIR/mapper/$vg-snap" "$mntdir"
+mount
+cat /proc/mounts | grep "$mntdir"
+dd if=/dev/zero of="$mntdir/file$1" bs=1M count=16
+sync
+#dmeventd only checks every 10 seconds :(
+for i in {1..10}; do
+       cat /proc/mounts | grep "$mntdir" || break
+       sleep 1
+done
+
+cat /proc/mounts | not grep "$mntdir"
+
+vgremove -f $vg
diff --git a/test/shell/snapshot-merge.sh b/test/shell/snapshot-merge.sh
new file mode 100644 (file)
index 0000000..a42b6f8
--- /dev/null
@@ -0,0 +1,122 @@
+#!/bin/sh
+# Copyright (C) 2010-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+which mkfs.ext3 || skip
+
+lvdev_() {
+    echo "$DM_DEV_DIR/$1/$2"
+}
+
+snap_lv_name_() {
+    echo ${1}_snap
+}
+
+setup_merge_() {
+    local VG_NAME=$1
+    local LV_NAME=$2
+    local NUM_EXTRA_SNAPS=${3:-0}
+    local BASE_SNAP_LV_NAME=$(snap_lv_name_ $LV_NAME)
+
+    lvcreate -n $LV_NAME -l 50%FREE $VG_NAME
+    lvcreate -s -n $BASE_SNAP_LV_NAME -l 20%FREE ${VG_NAME}/${LV_NAME}
+    mkfs.ext3 "$(lvdev_ $VG_NAME $LV_NAME)"
+
+    if [ $NUM_EXTRA_SNAPS -gt 0 ]; then
+       for i in `seq 1 $NUM_EXTRA_SNAPS`; do
+           lvcreate -s -n ${BASE_SNAP_LV_NAME}_${i} -l 20%FREE ${VG_NAME}/${LV_NAME}
+       done
+    fi
+}
+
+aux prepare_vg 1 100
+mkdir test_mnt
+
+# test full merge of a single LV
+setup_merge_ $vg $lv1
+# now that snapshot LV is created: test if snapshot-merge target is available
+aux target_at_least snapshot-merge 1 0 0 || skip
+
+# make sure lvconvert --merge requires explicit LV listing
+not lvconvert --merge 2>err
+lvconvert --merge $vg/$(snap_lv_name_ $lv1)
+lvremove -f $vg/$lv1
+
+
+# test that an actively merging snapshot may not be removed
+setup_merge_ $vg $lv1
+lvconvert -i+100 --merge --background $vg/$(snap_lv_name_ $lv1)
+not lvremove -f $vg/$(snap_lv_name_ $lv1)
+lvremove -f $vg/$lv1
+
+
+# "onactivate merge" test
+setup_merge_ $vg $lv1
+mount "$(lvdev_ $vg $lv1)" test_mnt
+lvconvert --merge $vg/$(snap_lv_name_ $lv1)
+# -- refresh LV while FS is still mounted (merge must not start),
+#    verify 'snapshot-origin' target is still being used
+lvchange --refresh $vg/$lv1
+umount test_mnt
+dm_table $vg-$lv1 | grep " snapshot-origin "
+
+# -- refresh LV to start merge (now that FS is unmounted),
+#    an active merge uses the 'snapshot-merge' target
+lvchange --refresh $vg/$lv1
+# check whether it's still merging - or maybe got already merged (slow test)
+dm_table $vg-$lv1 | grep " snapshot-merge " || dm_table $vg-$lv1 | grep " linear "
+# -- don't care if merge is still active; lvremove at this point
+#    may test stopping an active merge
+lvremove -f $vg/$lv1
+
+
+# "onactivate merge" test
+# -- deactivate/remove after disallowed merge attempt, tests
+#    to make sure preload of origin's metadata is _not_ performed
+setup_merge_ $vg $lv1
+mount "$(lvdev_ $vg $lv1)" test_mnt
+lvconvert --merge $vg/$(snap_lv_name_ $lv1)
+# -- refresh LV while FS is still mounted (merge must not start),
+#    verify 'snapshot-origin' target is still being used
+lvchange --refresh $vg/$lv1
+umount test_mnt
+dm_table $vg-$lv1 | grep " snapshot-origin " >/dev/null
+lvremove -f $vg/$lv1
+
+
+# test multiple snapshot merge; tests copy out that is driven by merge
+setup_merge_ $vg $lv1 1
+lvconvert --merge $vg/$(snap_lv_name_ $lv1)
+lvremove -f $vg/$lv1
+
+
+# test merging multiple snapshots that share the same tag
+setup_merge_ $vg $lv1
+setup_merge_ $vg $lv2
+lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv1)
+lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv2)
+lvconvert --merge @this_is_a_test
+lvs $vg >out
+not grep $(snap_lv_name_ $lv1) out
+not grep $(snap_lv_name_ $lv2) out
+lvremove -f $vg/$lv1 $vg/$lv2
+
+# FIXME following tests would need to poll merge progress, via periodic lvs?
+# Background processes don't lend themselves to lvm testsuite...
+
+# test: onactivate merge of a single lv
+
+# test: do onactivate, deactivate the origin LV, reactivate the LV, merge should resume
+
+# test: multiple onactivate merge
+
+vgremove -f $vg
diff --git a/test/shell/snapshots-of-mirrors.sh b/test/shell/snapshots-of-mirrors.sh
new file mode 100644 (file)
index 0000000..183d3ac
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_vg 4
+
+# Attempt to create snapshot of a mirror origin - should fail
+lvcreate -m 1 -L 10M -n lv $vg
+
+lvcreate -s $vg/lv -L 10M -n snap
+
+# Down-convert (mirror -> linear) under a snapshot
+lvconvert -m0 $vg/lv
+
+# Up-convert (linear -> mirror)
+lvconvert -m2 $vg/lv
+
+# Down-convert (mirror -> mirror)
+lvconvert -m1 $vg/lv
+
+# Up-convert (mirror -> mirror) -- Not supported!
+not lvconvert -m2 $vg/lv
+
+# Log conversion (disk -> core)
+lvconvert --mirrorlog core $vg/lv
+
+# Log conversion (core -> mirrored)
+lvconvert --mirrorlog mirrored $vg/lv
+
+# Log conversion (mirrored -> core)
+lvconvert --mirrorlog core $vg/lv
+
+# Log conversion (core -> disk)
+lvconvert --mirrorlog disk $vg/lv
+
+## Clean-up
+vgremove -f $vg
diff --git a/test/shell/tags.sh b/test/shell/tags.sh
new file mode 100644 (file)
index 0000000..6c35fc3
--- /dev/null
@@ -0,0 +1,73 @@
+#!/bin/sh
+# Copyright (C) 2008-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_pvs 4
+
+# vgcreate with --addtag
+vgcreate -c n --addtag firstvg $vg1 "$dev1" "$dev2"
+vgcreate -c n --addtag secondvg $vg2 "$dev3" "$dev4"
+check vg_field $vg1 tags "firstvg"
+check vg_field $vg2 tags "secondvg"
+vgremove -f $vg1 $vg2
+
+# vgchange with --addtag and --deltag
+vgcreate -c n $vg1 "$dev1" "$dev2"
+vgcreate -c n $vg2 "$dev3" "$dev4"
+vgchange --addtag firstvgtag1 $vg1
+# adding a tag multiple times is not an error
+vgchange --addtag firstvgtag2 $vg1
+vgchange --addtag firstvgtag2 $vg1
+vgchange --addtag firstvgtag3 $vg1
+vgchange --addtag secondvgtag1 $vg2
+vgchange --addtag secondvgtag2 $vg2
+vgchange --addtag secondvgtag3 $vg2
+check vg_field @firstvgtag2 tags "firstvgtag1,firstvgtag2,firstvgtag3"
+check vg_field @secondvgtag1 tags "secondvgtag1,secondvgtag2,secondvgtag3"
+vgchange --deltag firstvgtag2 $vg1
+check vg_field @firstvgtag1 tags "firstvgtag1,firstvgtag3"
+# deleting a tag multiple times is not an error
+vgchange --deltag firstvgtag2 $vg1
+vgchange --deltag firstvgtag1 $vg2
+vgremove -f $vg1 $vg2
+
+# lvcreate with --addtag
+vgcreate -c n $vg1 "$dev1" "$dev2"
+lvcreate --addtag firstlvtag1 -l 4 -n $lv1 $vg1
+lvcreate --addtag secondlvtag1 -l 4 -n $lv2 $vg1
+check lv_field @firstlvtag1 tags "firstlvtag1"
+not check lv_field @secondlvtag1 tags "firstlvtag1"
+check lv_field $vg1/$lv2 tags "secondlvtag1"
+not check lv_field $vg1/$lv1 tags "secondlvtag1"
+vgremove -f $vg1
+
+# lvchange with --addtag and --deltag
+vgcreate -c n $vg1 "$dev1" "$dev2"
+lvcreate -l 4 -n $lv1 $vg1
+lvcreate -l 4 -n $lv2 $vg1
+lvchange --addtag firstlvtag1 $vg1/$lv1
+# adding a tag multiple times is not an error
+lvchange --addtag firstlvtag2 $vg1/$lv1
+lvchange --addtag firstlvtag2 $vg1/$lv1
+lvchange --addtag firstlvtag3 $vg1/$lv1
+lvchange --addtag secondlvtag1 $vg1/$lv2
+lvchange --addtag secondlvtag2 $vg1/$lv2
+lvchange --addtag secondlvtag3 $vg1/$lv2
+check lv_field $vg1/$lv1 tags "firstlvtag1,firstlvtag2,firstlvtag3"
+not check lv_field $vg1/$lv1 tags "secondlvtag1"
+check lv_field $vg1/$lv2 tags "secondlvtag1,secondlvtag2,secondlvtag3"
+not check lv_field $vg1/$lv1 tags "secondlvtag1"
+# deleting a tag multiple times is not an error
+lvchange --deltag firstlvtag2 $vg1/$lv1
+lvchange --deltag firstlvtag2 $vg1/$lv1
+check lv_field $vg1/$lv1 tags "firstlvtag1,firstlvtag3"
+check lv_field $vg1/$lv2 tags "secondlvtag1,secondlvtag2,secondlvtag3"
diff --git a/test/shell/test-partition.sh b/test/shell/test-partition.sh
new file mode 100644 (file)
index 0000000..f7e91b8
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+#
+# Testcase for bugzilla #621173 
+# excercises partition table scanning code path
+#
+
+
+LVM_TEST_CONFIG_DEVICES="types = [\"device-mapper\", 142]"
+
+. lib/test
+
+which sfdisk || skip
+
+aux prepare_pvs 1 30
+
+pvs "$dev1"
+
+# create small partition table
+echo "1 2" | sfdisk "$dev1"
+
+pvs "$dev1"
diff --git a/test/shell/thin-autoumount-dmeventd.sh b/test/shell/thin-autoumount-dmeventd.sh
new file mode 100644 (file)
index 0000000..bbffe8a
--- /dev/null
@@ -0,0 +1,70 @@
+#!/bin/bash
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# no automatic extensions, just umount
+
+is_dir_mounted_()
+{
+       cat /proc/mounts | sed 's:\\040: :g' | grep "$1"
+}
+
+. lib/test
+
+#
+# Main
+#
+which mkfs.ext2 || skip
+
+aux have_thin 1 0 0 || skip
+
+aux prepare_dmeventd
+
+aux lvmconf "activation/thin_pool_autoextend_percent = 0" \
+            "activation/thin_pool_autoextend_threshold = 70"
+
+aux prepare_vg 2
+
+mntdir="${PREFIX}mnt with space"
+mntusedir="${PREFIX}mntuse"
+
+lvcreate -L8M -V8M -n $lv1 -T $vg/pool
+lvcreate -V8M -n $lv2 -T $vg/pool
+
+mkfs.ext2 "$DM_DEV_DIR/$vg/$lv1"
+mkfs.ext2 "$DM_DEV_DIR/$vg/$lv2"
+
+lvchange --monitor y $vg/pool
+
+mkdir "$mntdir" "$mntusedir"
+mount "$DM_DEV_DIR/mapper/$vg-$lv1" "$mntdir"
+mount "$DM_DEV_DIR/mapper/$vg-$lv2" "$mntusedir"
+
+is_dir_mounted_ "$mntdir"
+
+# fill above 70%
+dd if=/dev/zero of="$mntdir/file$$" bs=1M count=6
+touch "$mntusedir/file$$"
+tail -f "$mntusedir/file$$" &
+PID_TAIL=$!
+sync
+lvs -a $vg
+sleep 12 # dmeventd only checks every 10 seconds :(
+
+lvs -a $vg
+# both dirs should be unmounted
+not is_dir_mounted "$mntdir"
+not is_dir_mounted "$mntusedir"
+
+# running tail keeps the block device still in use
+kill $PID_TAIL
+lvs -a $vg
+
+vgremove -f $vg
diff --git a/test/shell/topology-support.sh b/test/shell/topology-support.sh
new file mode 100644 (file)
index 0000000..e952dc0
--- /dev/null
@@ -0,0 +1,105 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+which mkfs.ext3 || skip
+
+check_logical_block_size() {
+    local DEV_=$(cat SCSI_DEBUG_DEV)
+    # Verify logical_block_size - requires Linux >= 2.6.31
+    SYSFS_LOGICAL_BLOCK_SIZE=$(echo /sys/block/$(basename $DEV_)/queue/logical_block_size)
+    if [ -f "$SYSFS_LOGICAL_BLOCK_SIZE" ] ; then
+       ACTUAL_LOGICAL_BLOCK_SIZE=$(cat $SYSFS_LOGICAL_BLOCK_SIZE)
+       test $ACTUAL_LOGICAL_BLOCK_SIZE = $1
+    fi
+}
+
+lvdev_() {
+    echo "$DM_DEV_DIR/$1/$2"
+}
+
+test_snapshot_mount() {
+    lvcreate -L 16M -n $lv1 $vg "$dev1"
+    mkfs.ext3 $(lvdev_ $vg $lv1)
+    mkdir test_mnt
+    mount "$(lvdev_ $vg $lv1)" test_mnt
+    lvcreate -L 16M -n $lv2 -s $vg/$lv1
+    umount test_mnt
+    # mount the origin
+    mount "$(lvdev_ $vg $lv1)" test_mnt
+    umount test_mnt
+    # mount the snapshot
+    mount "$(lvdev_ $vg $lv2)" test_mnt
+    umount test_mnt
+    rm -r test_mnt
+    vgchange -an $vg
+    lvremove -f $vg/$lv2
+    lvremove -f $vg/$lv1
+}
+
+# FIXME add more topology-specific tests and validation (striped LVs, etc)
+
+NUM_DEVS=1
+PER_DEV_SIZE=34
+DEV_SIZE=$(($NUM_DEVS*$PER_DEV_SIZE))
+
+# Test that kernel supports topology
+aux prepare_scsi_debug_dev $DEV_SIZE || skip
+
+if [ ! -e /sys/block/$(basename $(cat SCSI_DEBUG_DEV))/alignment_offset ] ; then
+       aux cleanup_scsi_debug_dev
+       skip
+fi
+aux cleanup_scsi_debug_dev
+
+# ---------------------------------------------
+# Create "desktop-class" 4K drive
+# (logical_block_size=512, physical_block_size=4096, alignment_offset=0):
+LOGICAL_BLOCK_SIZE=512
+aux prepare_scsi_debug_dev $DEV_SIZE \
+    sector_size=$LOGICAL_BLOCK_SIZE physblk_exp=3
+check_logical_block_size $LOGICAL_BLOCK_SIZE
+
+aux prepare_pvs $NUM_DEVS $PER_DEV_SIZE
+vgcreate -c n $vg $(cat DEVICES)
+test_snapshot_mount
+vgremove $vg
+
+aux cleanup_scsi_debug_dev
+
+# ---------------------------------------------
+# Create "desktop-class" 4K drive w/ 63-sector DOS partition compensation
+# (logical_block_size=512, physical_block_size=4096, alignment_offset=3584):
+LOGICAL_BLOCK_SIZE=512
+aux prepare_scsi_debug_dev $DEV_SIZE \
+    sector_size=$LOGICAL_BLOCK_SIZE physblk_exp=3 lowest_aligned=7
+check_logical_block_size $LOGICAL_BLOCK_SIZE
+
+aux prepare_pvs $NUM_DEVS $PER_DEV_SIZE
+vgcreate -c n $vg $(cat DEVICES)
+test_snapshot_mount
+vgremove $vg
+
+aux cleanup_scsi_debug_dev
+
+# ---------------------------------------------
+# Create "enterprise-class" 4K drive
+# (logical_block_size=4096, physical_block_size=4096, alignment_offset=0):
+LOGICAL_BLOCK_SIZE=4096
+aux prepare_scsi_debug_dev $DEV_SIZE \
+    sector_size=$LOGICAL_BLOCK_SIZE
+check_logical_block_size $LOGICAL_BLOCK_SIZE
+
+aux prepare_pvs $NUM_DEVS $PER_DEV_SIZE
+vgcreate -c n $vg $(cat DEVICES)
+test_snapshot_mount
+vgremove $vg
diff --git a/test/shell/unknown-segment.sh b/test/shell/unknown-segment.sh
new file mode 100644 (file)
index 0000000..d6071a1
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/sh
+# Copyright (C) 2009 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_vg 4
+
+lvcreate -l 1 -n $lv1 $vg
+lvcreate -l 2 -m 1 -n $lv2 $vg
+
+vgcfgbackup -f bak0 $vg
+sed -e 's,striped,unstriped,;s,mirror,unmirror,' -i.orig bak0
+vgcfgrestore -f bak0 $vg
+
+# we have on-disk metadata with unknown segments now
+not lvchange -a y $vg/$lv1 # check that activation is refused
+
+vgcfgbackup -f bak1 $vg
+cat bak1
+sed -e 's,unstriped,striped,;s,unmirror,mirror,' -i.orig bak1
+vgcfgrestore -f bak1 $vg
+vgcfgbackup -f bak2 $vg
+
+egrep -v 'description|seqno|creation_time|Generated' < bak0.orig > a
+egrep -v 'description|seqno|creation_time|Generated' < bak2 > b
+diff -u a b
diff --git a/test/shell/unlost-pv.sh b/test/shell/unlost-pv.sh
new file mode 100644 (file)
index 0000000..962fe22
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+check_() {
+       # vgscan needs --cache option for direct scan if lvmetad is used
+       test -e LOCAL_LVMETAD && cache="--cache"
+       vgscan $cache 2>&1 | tee vgscan.out
+       $1 grep "Inconsistent metadata found for VG $vg" vgscan.out
+}
+
+aux prepare_vg 3
+
+lvcreate -m 1 -l 1 -n mirror $vg
+lvchange -a n $vg
+
+# try orphaning a missing PV (bz45867)
+aux disable_dev "$dev1"
+vgreduce --removemissing --force $vg
+aux enable_dev "$dev1"
+
+check_
+test -e LOCAL_LVMETAD && pvcreate -f "$dev1"
+check_ not
+
+# try to just change metadata; we expect the new version (with MISSING_PV set
+# on the reappeared volume) to be written out to the previously missing PV
+vgextend $vg "$dev1"
+lvcreate -l 1 -n boo -a n --zero n $vg
+aux disable_dev "$dev1"
+lvremove $vg/mirror
+aux enable_dev "$dev1"
+check_
+test -e LOCAL_LVMETAD && lvremove $vg/boo # FIXME trigger a write :-(
+check_ not
diff --git a/test/shell/vgcfgbackup-usage.sh b/test/shell/vgcfgbackup-usage.sh
new file mode 100644 (file)
index 0000000..c8245b0
--- /dev/null
@@ -0,0 +1,53 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_pvs 4
+
+# vgcfgbackup handles similar VG names (bz458941)
+vg1=${PREFIX}vg00
+vg2=${PREFIX}vg01
+vgcreate $vg1 "$dev1"
+vgcreate $vg2 "$dev2"
+vgcfgbackup -f $TESTDIR/bak-%s >out
+grep "Volume group \"$vg1\" successfully backed up." out
+grep "Volume group \"$vg2\" successfully backed up." out
+vgremove -ff $vg1 $vg2
+
+# vgcfgbackup correctly stores metadata with missing PVs
+# and vgcfgrestore able to restore them when device reappears
+pv1_uuid=$(get pv_field "$dev1" pv_uuid)
+pv2_uuid=$(get pv_field "$dev2" pv_uuid)
+vgcreate $vg $(cat DEVICES)
+lvcreate -l1 -n $lv1 $vg "$dev1"
+lvcreate -l1 -n $lv2 $vg "$dev2"
+lvcreate -l1 -n $lv3 $vg "$dev3"
+vgchange -a n $vg
+pvcreate -ff -y "$dev1"
+pvcreate -ff -y "$dev2"
+vgcfgbackup -f "$(pwd)/backup.$$" $vg
+sed 's/flags = \[\"MISSING\"\]/flags = \[\]/' "$(pwd)/backup.$$" > "$(pwd)/backup.$$1"
+pvcreate -ff -y --norestorefile -u $pv1_uuid "$dev1"
+pvcreate -ff -y --norestorefile -u $pv2_uuid "$dev2"
+vgcfgrestore -f "$(pwd)/backup.$$1" $vg
+vgremove -ff $vg
+
+# vgcfgbackup correctly stores metadata LVM1 with missing PVs
+# FIXME: clvmd seems to have problem with metadata format change here
+# fix it and remove this vgscan
+vgscan
+pvcreate -M1 $(cat DEVICES)
+vgcreate -M1 -c n $vg $(cat DEVICES)
+lvcreate -l1 -n $lv1 $vg "$dev1"
+pvremove -ff -y "$dev2"
+not lvcreate -l1 -n $lv1 $vg "$dev3"
+vgcfgbackup -f "$(pwd)/backup.$$" $vg
diff --git a/test/shell/vgchange-maxlv.sh b/test/shell/vgchange-maxlv.sh
new file mode 100644 (file)
index 0000000..413fef9
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_dmeventd
+aux prepare_pvs 3
+
+vgcreate -c n -l 2 $vg $(cat DEVICES)
+lvcreate -n one -l 1 $vg
+lvcreate -n two -l 1 $vg
+not lvcreate -n three -l 1 $vg
+vgremove -ff $vg
+
+vgcreate -c n -l 3 $vg $(cat DEVICES)
+lvcreate -n one -l 1 $vg
+lvcreate -n snap -s -l 1 $vg/one
+lvcreate -n two -l 1 $vg
+not lvcreate -n three -l 1 $vg
+vgchange --monitor y $vg
+vgchange -an $vg 2>&1 | tee vgchange.out
+not grep "event server" vgchange.out
diff --git a/test/shell/vgchange-partial.sh b/test/shell/vgchange-partial.sh
new file mode 100644 (file)
index 0000000..5b21a40
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/bash
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_vg 2
+
+aux disable_dev "$dev1"
+
+#
+# Test for allowable metadata changes
+# addtag_ARG
+# deltag_ARG
+vgchange --addtag foo $vg
+vgchange --deltag foo $vg
+
+#
+# Test for disallowed metadata changes
+#
+# maxphysicalvolumes_ARG
+not vgchange -p 10 $vg
+
+# resizeable_ARG
+not vgchange -x n $vg
+
+# uuid_ARG
+not vgchange -u $vg
+
+# physicalextentsize_ARG
+not vgchange -s 2M $vg
+
+# clustered_ARG
+not vgchange -c y $vg
+
+# alloc_ARG
+not vgchange --alloc anywhere $vg
+
+# vgmetadatacopies_ARG
+not vgchange --vgmetadatacopies 2 $vg
+
+#
+# Ensure that allowed args don't cause disallowed args to get through
+#
+not vgchange -p 10 --addtag foo $vg
diff --git a/test/shell/vgchange-sysinit.sh b/test/shell/vgchange-sysinit.sh
new file mode 100644 (file)
index 0000000..d7a166c
--- /dev/null
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+which mkfs.ext3 || skip
+
+aux prepare_pvs 2 8
+test -e LOCAL_CLVMD && skip
+
+var_lock="$DM_DEV_DIR/$vg1/$lv1"
+# keep in sync with aux configured lockingdir
+mount_dir="var/lock/lvm"
+
+cleanup_mounted_and_teardown()
+{
+       umount "$mount_dir" || true
+       aux teardown
+}
+
+vgcreate -c n $vg1 "$dev1"
+vgcreate -c n $vg2 "$dev2"
+
+lvcreate -l 1 -n $lv2 $vg2
+vgchange -an $vg2
+
+lvcreate -n $lv1 -l 100%FREE $vg1
+mkfs.ext3 -b4096 -j "$var_lock"
+
+trap 'cleanup_mounted_and_teardown' EXIT
+mount -n -r "$var_lock" "$mount_dir"
+
+# locking must fail on read-only filesystem
+not vgchange -ay $vg2
+
+# no-locking with --sysinit
+vgchange --sysinit -ay $vg2
+test -b "$DM_DEV_DIR/$vg2/$lv2"
+
+vgchange --sysinit -an $vg2
+test ! -b "$DM_DEV_DIR/$vg2/$lv2"
+
+vgchange --ignorelockingfailure -ay $vg2
diff --git a/test/shell/vgchange-usage.sh b/test/shell/vgchange-usage.sh
new file mode 100644 (file)
index 0000000..a7bd488
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+test_description='Exercise some vgchange diagnostics'
+
+. lib/test
+
+aux prepare_pvs 3
+pvcreate --metadatacopies 0 "$dev1"
+vgcreate $vg $(cat DEVICES)
+
+vgdisplay $vg
+
+# vgchange -p MaxPhysicalVolumes (bz202232)
+aux check vg_field $vg max_pv 0
+vgchange -p 128 $vg
+aux check vg_field $vg max_pv 128
+
+pv_count=$(get vg_field $vg pv_count)
+not vgchange -p 2 $vg 2>err
+grep "MaxPhysicalVolumes is less than the current number $pv_count of PVs for" err
+aux check vg_field $vg max_pv 128
+
+# vgchange -l MaxLogicalVolumes
+aux check vg_field $vg max_lv 0
+vgchange -l 128 $vg
+aux check vg_field $vg max_lv 128
+
+lvcreate -l4 -n $lv1 $vg
+lvcreate -l4 -n $lv2 $vg
+
+lv_count=$(get vg_field $vg lv_count)
+not vgchange -l 1 $vg 2>err
+grep "MaxLogicalVolume is less than the current number $lv_count of LVs for"  err
+aux check vg_field $vg max_lv 128
+
diff --git a/test/shell/vgcreate-usage.sh b/test/shell/vgcreate-usage.sh
new file mode 100644 (file)
index 0000000..db80f0f
--- /dev/null
@@ -0,0 +1,163 @@
+#!/bin/sh
+# Copyright (C) 2008-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+test_description='Exercise some vgcreate diagnostics'
+
+. lib/test
+
+aux prepare_devs 3
+pvcreate "$dev1" "$dev2"
+pvcreate --metadatacopies 0 "$dev3"
+
+vg=${PREFIX}vg
+
+#COMM 'vgcreate accepts 8.00m physicalextentsize for VG'
+vgcreate -c n $vg --physicalextentsize 8.00m "$dev1" "$dev2"
+check vg_field  $vg vg_extent_size 8.00m
+vgremove $vg
+# try vgck and to remove it again - should fail (but not segfault)
+not vgremove $vg
+not vgck $vg
+
+#COMM 'vgcreate accepts smaller (128) maxlogicalvolumes for VG'
+vgcreate -c n $vg --maxlogicalvolumes 128 "$dev1" "$dev2" 
+check vg_field $vg max_lv 128 
+vgremove $vg
+
+#COMM 'vgcreate accepts smaller (128) maxphysicalvolumes for VG'
+vgcreate -c n $vg --maxphysicalvolumes 128 "$dev1" "$dev2"
+check vg_field $vg max_pv 128
+vgremove $vg
+
+#COMM 'vgcreate rejects a zero physical extent size'
+not vgcreate -c n --physicalextentsize 0 $vg "$dev1" "$dev2" 2>err
+grep "Physical extent size may not be zero" err
+
+#COMM 'vgcreate rejects "inherit" allocation policy'
+not vgcreate -c n --alloc inherit $vg "$dev1" "$dev2" 2>err
+grep "Volume Group allocation policy cannot inherit from anything" err
+
+#COMM 'vgcreate rejects vgname "."'
+vginvalid=.; 
+not vgcreate -c n $vginvalid "$dev1" "$dev2" 2>err
+grep "New volume group name \"$vginvalid\" is invalid" err
+
+#COMM 'vgcreate rejects vgname greater than 128 characters'
+vginvalid=thisnameisridiculouslylongtotestvalidationcodecheckingmaximumsizethisiswhathappenswhenprogrammersgetboredandorarenotcreativedonttrythisathome
+not vgcreate -c n $vginvalid "$dev1" "$dev2" 2>err
+grep "New volume group name \"$vginvalid\" is invalid" err
+
+#COMM 'vgcreate rejects already existing vgname "/tmp/$vg"'
+#touch /tmp/$vg
+#not vgcreate $vg "$dev1" "$dev2" 2>err
+#grep "New volume group name \"$vg\" is invalid\$" err
+
+#COMM "vgcreate rejects repeated invocation (run 2 times) (bz178216)"
+vgcreate -c n $vg "$dev1" "$dev2"
+not vgcreate -c n $vg "$dev1" "$dev2"
+vgremove -ff $vg
+
+#COMM 'vgcreate rejects MaxLogicalVolumes > 255'
+not vgcreate -c n --metadatatype 1 --maxlogicalvolumes 1024 $vg "$dev1" "$dev2" 2>err
+grep "Number of volumes may not exceed 255" err
+
+#COMM "vgcreate fails when the only pv has --metadatacopies 0"
+not vgcreate -c n $vg "$dev3"
+
+# Test default (4MB) vg_extent_size as well as limits of extent_size
+not vgcreate -c n --physicalextentsize 0k $vg "$dev1" "$dev2"
+vgcreate -c n --physicalextentsize 1k $vg "$dev1" "$dev2"
+check vg_field $vg vg_extent_size 1.00k
+vgremove -ff $vg
+not vgcreate -c n --physicalextentsize 3K $vg "$dev1" "$dev2"
+not vgcreate -c n --physicalextentsize 1024t $vg "$dev1" "$dev2"
+#not vgcreate --physicalextentsize 1T $vg "$dev1" "$dev2"
+# FIXME: vgcreate allows physicalextentsize larger than pv size!
+
+# Test default max_lv, max_pv, extent_size, alloc_policy, clustered
+vgcreate -c n $vg "$dev1" "$dev2"
+check vg_field $vg vg_extent_size 4.00m
+check vg_field $vg max_lv 0
+check vg_field $vg max_pv 0
+check vg_field $vg vg_attr "wz--n-"
+vgremove -ff $vg
+
+# Implicit pvcreate tests, test pvcreate options on vgcreate
+# --force, --yes, --metadata{size|copies|type}, --zero
+# --dataalignment[offset]
+pvremove "$dev1" "$dev2"
+vgcreate -c n --force --yes --zero y $vg "$dev1" "$dev2"
+vgremove -f $vg
+pvremove -f "$dev1"
+
+for i in 0 1 2 3
+do
+# vgcreate (lvm2) succeeds writing LVM label at sector $i
+    vgcreate -c n --labelsector $i $vg "$dev1"
+    dd if="$dev1" bs=512 skip=$i count=1 2>/dev/null | strings | grep LABELONE >/dev/null
+    vgremove -f $vg
+    pvremove -f "$dev1"
+done
+
+# pvmetadatacopies
+for i in 1 2
+do
+    vgcreate -c n --pvmetadatacopies $i $vg "$dev1"
+    check pv_field "$dev1" pv_mda_count $i
+    vgremove -f $vg
+    pvremove -f "$dev1"
+done
+not vgcreate -c n --pvmetadatacopies 0 $vg "$dev1"
+pvcreate --metadatacopies 1 "$dev2"
+vgcreate -c n --pvmetadatacopies 0 $vg "$dev1" "$dev2"
+check pv_field "$dev1" pv_mda_count 0
+check pv_field "$dev2" pv_mda_count 1
+vgremove -f $vg
+pvremove -f "$dev1"
+
+# metadatasize, dataalignment, dataalignmentoffset
+#COMM 'pvcreate sets data offset next to mda area'
+vgcreate -c n --metadatasize 100k --dataalignment 100k $vg "$dev1"
+check pv_field "$dev1" pe_start 200.00k
+vgremove -f $vg
+pvremove -f "$dev1"
+
+# data area is aligned to 1M by default,
+# data area start is shifted by the specified alignment_offset
+pv_align=1052160 # 1048576 + (7*512)
+vgcreate -c n --metadatasize 128k --dataalignmentoffset 7s $vg "$dev1"
+check pv_field "$dev1" pe_start ${pv_align}B --units b
+vgremove -f $vg
+pvremove -f "$dev1"
+
+# metadatatype
+for i in 1 2
+do
+    vgcreate -c n -M $i $vg "$dev1"
+    check vg_field $vg vg_fmt lvm$i
+    vgremove -f $vg
+    pvremove -f "$dev1"
+done
+
+# vgcreate fails if pv belongs to existing vg
+vgcreate -c n $vg1 "$dev1" "$dev2"
+not vgcreate $vg2 "$dev2"
+vgremove -f $vg1
+pvremove -f "$dev1" "$dev2"
+
+# all PVs exist in the VG after created
+pvcreate "$dev1"
+vgcreate -c n $vg1 "$dev1" "$dev2" "$dev3"
+check pv_field "$dev1" vg_name $vg1
+check pv_field "$dev2" vg_name $vg1
+check pv_field "$dev3" vg_name $vg1
+vgremove -f $vg1
+pvremove -f "$dev1" "$dev2" "$dev3"
diff --git a/test/shell/vgextend-restoremissing.sh b/test/shell/vgextend-restoremissing.sh
new file mode 100644 (file)
index 0000000..fae68e4
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_vg 3
+
+lvcreate -m 1 -l 1 -n mirror $vg
+lvchange -a n $vg/mirror
+lvcreate -l 1 -n lv1 $vg "$dev1"
+
+# try to just change metadata; we expect the new version (with MISSING_PV set
+# on the reappeared volume) to be written out to the previously missing PV
+aux disable_dev "$dev1"
+lvremove $vg/mirror
+aux enable_dev "$dev1"
+not vgck $vg 2>&1 | tee log
+grep "missing 1 physical volume" log
+not lvcreate -m 1 -l 1 -n mirror $vg # write operations fail
+vgextend --restore $vg "$dev1" # restore the missing device
+vgck $vg
+lvcreate -m 1 -l 1 -n mirror $vg
diff --git a/test/shell/vgextend-usage.sh b/test/shell/vgextend-usage.sh
new file mode 100644 (file)
index 0000000..0e347c3
--- /dev/null
@@ -0,0 +1,130 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+#
+# Exercise various vgextend commands
+#
+
+. lib/test
+
+aux prepare_devs 5
+
+for mdatype in 1 2
+do
+
+# Explicit pvcreate
+pvcreate -M$mdatype "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+vgcreate -M$mdatype $vg1 "$dev1" "$dev2"
+vgextend $vg1 "$dev3" "$dev4" "$dev5"
+vgremove -ff $vg1
+
+# Implicit pvcreate
+pvremove "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+vgcreate -M$mdatype $vg1 "$dev1" "$dev2"
+vgextend -M$mdatype $vg1 "$dev3" "$dev4" "$dev5"
+vgremove -ff $vg1
+pvremove "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+
+done
+
+# Implicit pvcreate tests, test pvcreate options on vgcreate
+# --force, --yes, --metadata{size|copies|type}, --zero
+# --dataalignment[offset]
+vgcreate $vg "$dev2"
+vgextend --force --yes --zero y $vg "$dev1"
+vgreduce $vg "$dev1"
+pvremove -f "$dev1"
+
+for i in 0 1 2 3
+do
+# vgcreate (lvm2) succeeds writing LVM label at sector $i
+    vgextend --labelsector $i $vg "$dev1"
+    dd if="$dev1" bs=512 skip=$i count=1 2>/dev/null | strings | grep LABELONE >/dev/null
+    vgreduce $vg "$dev1"
+    pvremove -f "$dev1"
+done
+
+# pvmetadatacopies
+for i in 0 1 2
+do
+    vgextend --pvmetadatacopies $i $vg "$dev1"
+    check pv_field "$dev1" pv_mda_count $i
+    vgreduce $vg "$dev1"
+    pvremove -f "$dev1"
+done
+
+# metadatasize, dataalignment, dataalignmentoffset
+#COMM 'pvcreate sets data offset next to mda area'
+vgextend --metadatasize 100k --dataalignment 100k $vg "$dev1"
+check pv_field "$dev1" pe_start 200.00k
+vgreduce $vg "$dev1"
+pvremove -f "$dev1"
+
+# data area is aligned to 1M by default,
+# data area start is shifted by the specified alignment_offset
+pv_align=1052160B # 1048576 + (7*512)
+vgextend --metadatasize 128k --dataalignmentoffset 7s $vg "$dev1"
+check pv_field "$dev1" pe_start $pv_align --units b
+vgremove -f $vg
+pvremove -f "$dev1"
+
+# vgextend fails if pv belongs to existing vg
+vgcreate $vg1 "$dev1" "$dev3"
+vgcreate $vg2 "$dev2"
+not vgextend $vg2 "$dev3"
+vgremove -f $vg1
+vgremove -f $vg2
+pvremove -f "$dev1" "$dev2" "$dev3"
+
+#vgextend fails if vg is not resizeable
+vgcreate $vg1 "$dev1" "$dev2"
+vgchange --resizeable n $vg1
+not vgextend $vg1 "$dev3"
+vgremove -f $vg1
+pvremove -f "$dev1" "$dev2"
+
+# all PVs exist in the VG after extended
+pvcreate "$dev1"
+vgcreate $vg1 "$dev2"
+vgextend $vg1 "$dev1" "$dev3"
+check pv_field "$dev1" vg_name $vg1
+check pv_field "$dev2" vg_name $vg1
+check pv_field "$dev3" vg_name $vg1
+vgremove -f $vg1
+pvremove -f "$dev1" "$dev2" "$dev3"
+
+echo test vgextend --metadataignore
+for mdacp in 1 2; do
+for ignore in y n; do
+       echo vgextend --metadataignore has proper mda_count and mda_used_count
+       vgcreate $vg "$dev3"
+       vgextend --metadataignore $ignore --pvmetadatacopies $mdacp $vg "$dev1" "$dev2"
+       check pv_field "$dev1" pv_mda_count $mdacp
+       check pv_field "$dev2" pv_mda_count $mdacp
+       if [ $ignore = y ]; then
+               check pv_field "$dev1" pv_mda_used_count 0
+               check pv_field "$dev2" pv_mda_used_count 0
+       else
+               check pv_field "$dev1" pv_mda_used_count $mdacp
+               check pv_field "$dev2" pv_mda_used_count $mdacp
+       fi
+       echo vg has proper vg_mda_count and vg_mda_used_count
+       check vg_field $vg vg_mda_count $(($mdacp * 2 + 1))
+       if [ $ignore = y ]; then
+               check vg_field $vg vg_mda_used_count 1
+       else
+               check vg_field $vg vg_mda_used_count $(($mdacp * 2 + 1))
+       fi
+       check vg_field $vg vg_mda_copies unmanaged
+       vgremove $vg
+       pvremove -ff "$dev1" "$dev2" "$dev3"
+done
+done
diff --git a/test/shell/vgimportclone.sh b/test/shell/vgimportclone.sh
new file mode 100644 (file)
index 0000000..9b1c121
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+# Copyright (C) 2010-2011 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_devs 2
+
+vgcreate -c n --metadatasize 128k $vg1 "$dev1"
+lvcreate -l100%FREE -n $lv1 $vg1
+
+# Clone the LUN
+dd if="$dev1" of="$dev2" bs=256K count=1
+aux notify_lvmetad "$dev2"
+
+# Verify pvs works on each device to give us vgname
+check pv_field "$dev1" vg_name $vg1
+check pv_field "$dev2" vg_name $vg1
+
+# Import the cloned PV to a new VG
+vgimportclone --basevgname $vg2 "$dev2"
+
+# We need to re-scan *both* $dev1 and $dev2 since a PV, as far as lvmetad is
+# concerned, can only live on a single device. With the last pvscan, we told it
+# that PV from $dev1 now lives on $dev2, but in fact this is not true anymore,
+# since we wrote a different PV over $dev2.
+aux notify_lvmetad "$dev2"
+aux notify_lvmetad "$dev1"
+
+# Verify we can activate / deactivate the LV from both VGs
+lvchange -ay $vg1/$lv1 $vg2/$lv1
+vgchange -an $vg1 $vg2
diff --git a/test/shell/vgmerge-operation.sh b/test/shell/vgmerge-operation.sh
new file mode 100644 (file)
index 0000000..bdd5000
--- /dev/null
@@ -0,0 +1,79 @@
+#!/bin/sh
+# Copyright (C) 2007-2012 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+test_description='Test vgmerge operation'
+
+. lib/test
+
+aux prepare_pvs 4 64
+
+# 'vgmerge succeeds with single linear LV in source VG'
+vgcreate -c n $vg1 "$dev1" "$dev2"
+vgcreate -c n $vg2 "$dev3" "$dev4"
+lvcreate -l 4 -n $lv1 $vg1 "$dev1"
+vgchange -an $vg1
+check pvlv_counts $vg1 2 1 0
+check pvlv_counts $vg2 2 0 0
+vgmerge $vg2 $vg1
+check pvlv_counts $vg2 4 1 0
+vgremove -f $vg2
+
+# 'vgmerge succeeds with single linear LV in source and destination VG'
+vgcreate -c n $vg1 "$dev1" "$dev2"
+vgcreate -c n $vg2 "$dev3" "$dev4"
+lvcreate -l 4 -n $lv1 $vg1
+lvcreate -l 4 -n $lv2 $vg2
+vgchange -an $vg1
+vgchange -an $vg2
+check pvlv_counts $vg1 2 1 0
+check pvlv_counts $vg2 2 1 0
+vgmerge $vg2 $vg1
+check pvlv_counts $vg2 4 2 0
+vgremove -f $vg2
+
+# 'vgmerge succeeds with linear LV + snapshots in source VG'
+vgcreate -c n $vg1 "$dev1" "$dev2"
+vgcreate -c n $vg2 "$dev3" "$dev4"
+lvcreate -l 16 -n $lv1 $vg1
+lvcreate -l 4 -s -n $lv2 $vg1/$lv1
+vgchange -an $vg1
+check pvlv_counts $vg1 2 2 1
+check pvlv_counts $vg2 2 0 0
+vgmerge $vg2 $vg1
+check pvlv_counts $vg2 4 2 1
+lvremove -f $vg2/$lv2
+vgremove -f $vg2
+
+# 'vgmerge succeeds with mirrored LV in source VG'
+vgcreate -c n $vg1 "$dev1" "$dev2" "$dev3"
+vgcreate -c n $vg2 "$dev4"
+lvcreate -l 4 -n $lv1 -m1 $vg1
+vgchange -an $vg1
+check pvlv_counts $vg1 3 1 0
+check pvlv_counts $vg2 1 0 0
+vgmerge $vg2 $vg1
+check pvlv_counts $vg2 4 1 0
+lvremove -f $vg2/$lv1
+vgremove -f $vg2
+
+# 'vgmerge rejects LV name collision'
+vgcreate -c n $vg1 "$dev1" "$dev2"
+vgcreate -c n $vg2 "$dev3" "$dev4"
+lvcreate -l 4 -n $lv1 $vg1
+lvcreate -l 4 -n $lv1 $vg2
+vgchange -an $vg1
+check pvlv_counts $vg1 2 1 0
+check pvlv_counts $vg2 2 1 0
+not vgmerge $vg2 $vg1 2>err
+grep "Duplicate logical volume name \"$lv1\" in \"$vg2\" and \"$vg1" err
+check pvlv_counts $vg1 2 1 0
+check pvlv_counts $vg2 2 1 0
+vgremove -f $vg1 $vg2
diff --git a/test/shell/vgmerge-usage.sh b/test/shell/vgmerge-usage.sh
new file mode 100644 (file)
index 0000000..17779b5
--- /dev/null
@@ -0,0 +1,67 @@
+#!/bin/sh
+# Copyright (C) 2008-2011 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# 'Test vgmerge command options for validity'
+
+. lib/test
+
+aux prepare_pvs 4
+
+# 'vgmerge normal operation'
+# ensure ordering does not matter
+vgcreate  $vg1 "$dev1" "$dev2"
+vgcreate  $vg2 "$dev3" "$dev4"
+vgmerge $vg1 $vg2
+vgremove $vg1
+vgcreate -c n $vg2 "$dev1" "$dev2"
+vgcreate -c n $vg1 "$dev3" "$dev4"
+vgmerge $vg2 $vg1
+vgremove $vg2
+
+# 'vgmerge rejects duplicate vg name'
+vgcreate  $vg1 "$dev1" "$dev2"
+vgcreate  $vg2 "$dev3" "$dev4"
+not vgmerge $vg1 $vg1 2>err
+grep "Duplicate volume group name \"$vg1\"\$" err
+vgremove $vg1 $vg2
+
+# 'vgmerge rejects vgs with incompatible extent_size'
+vgcreate  --physicalextentsize 4M $vg1 "$dev1" "$dev2"
+vgcreate  --physicalextentsize 8M $vg2 "$dev3" "$dev4"
+not vgmerge $vg1 $vg2 2>err
+grep "Extent sizes differ" err
+vgremove $vg1 $vg2
+
+# 'vgmerge rejects vgmerge because max_pv is exceeded'
+vgcreate  --maxphysicalvolumes 2 $vg1 "$dev1" "$dev2"
+vgcreate  --maxphysicalvolumes 2 $vg2 "$dev3" "$dev4"
+not vgmerge $vg1 $vg2 2>err
+grep "Maximum number of physical volumes (2) exceeded" err
+vgremove $vg1 $vg2
+
+# 'vgmerge rejects vg with active lv'
+vgcreate $vg1 "$dev1" "$dev2"
+vgcreate $vg2 "$dev3" "$dev4"
+lvcreate -l 4 -n lv1 $vg2
+not vgmerge $vg1 $vg2 2>err
+grep "Logical volumes in \"$vg2\" must be inactive" err
+vgremove -f $vg1 $vg2
+
+# 'vgmerge rejects vgmerge because max_lv is exceeded'
+vgcreate --maxlogicalvolumes 2 $vg1 "$dev1" "$dev2"
+vgcreate --maxlogicalvolumes 2 $vg2 "$dev3" "$dev4"
+lvcreate -l 4 -n lv1 $vg1
+lvcreate -l 4 -n lv2 $vg1
+lvcreate -l 4 -n lv3 $vg2
+vgchange -an $vg1 $vg2
+not vgmerge $vg1 $vg2 2>err
+grep "Maximum number of logical volumes (2) exceeded" err
+vgremove -f $vg1 $vg2
diff --git a/test/shell/vgreduce-removemissing-snapshot.sh b/test/shell/vgreduce-removemissing-snapshot.sh
new file mode 100644 (file)
index 0000000..488d8fe
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+exit 0
+
+#
+# Snapshots of 'mirrors' are not supported.  They can no longer be created.
+# This file could be used to test some aspect of vgreduce, snapshot, and
+# RAID at some point though...
+#
+
+aux prepare_vg 5
+
+lvcreate -m 3 --ig -L 2M -n 4way $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5":0
+lvcreate -s $vg/4way -L 2M -n snap
+lvcreate -i 2 -L 2M $vg "$dev1" "$dev2" -n stripe
+
+aux disable_dev "$dev2" "$dev4"
+echo n | lvconvert --repair $vg/4way
+aux enable_dev "$dev2" "$dev4"
+#not vgreduce --removemissing $vg
+vgreduce -v --removemissing --force $vg # "$dev2" "$dev4"
+lvs -a -o +devices $vg | not grep unknown
+lvs -a -o +devices $vg
+check mirror $vg 4way "$dev5"
diff --git a/test/shell/vgreduce-usage.sh b/test/shell/vgreduce-usage.sh
new file mode 100644 (file)
index 0000000..9a55d3c
--- /dev/null
@@ -0,0 +1,89 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_devs 4
+
+for mdatype in 1 2
+do
+    # setup PVs
+    pvcreate -M$mdatype "$dev1" "$dev2"
+
+    # (lvm$mdatype) vgreduce removes only the specified pv from vg (bz427382)" '
+    vgcreate -c n -M$mdatype $vg1 "$dev1" "$dev2"
+    vgreduce $vg1 "$dev1"
+    check pv_field "$dev2" vg_name $vg1
+    vgremove -f $vg1
+
+    # (lvm$mdatype) vgreduce rejects removing the last pv (--all)
+    vgcreate -c n -M$mdatype $vg1 "$dev1" "$dev2"
+    not vgreduce --all $vg1
+    vgremove -f $vg1
+
+    # (lvm$mdatype) vgreduce rejects removing the last pv
+    vgcreate -c n -M$mdatype $vg1 "$dev1" "$dev2"
+    not vgreduce $vg1 "$dev1" "$dev2"
+    vgremove -f $vg1
+
+    pvremove -ff "$dev1" "$dev2"
+done
+
+mdatype=2 # we only expect the following to work for lvm2 metadata
+
+# (lvm$mdatype) setup PVs (--metadatacopies 0)
+pvcreate -M$mdatype "$dev1" "$dev2"
+pvcreate --metadatacopies 0 -M$mdatype "$dev3" "$dev4"
+
+# (lvm$mdatype) vgreduce rejects removing pv with the last mda copy (bz247448)
+vgcreate -c n -M$mdatype $vg1 "$dev1" "$dev3"
+not vgreduce $vg1 "$dev1"
+vgremove -f $vg1
+
+#COMM "(lvm$mdatype) vgreduce --removemissing --force repares to linear (bz221921)"
+# (lvm$mdatype) setup: create mirror & damage one pv
+vgcreate -c n -M$mdatype $vg1 "$dev1" "$dev2" "$dev3"
+lvcreate -n $lv1 -m1 -l 4 $vg1
+lvcreate -n $lv2  -l 4 $vg1 "$dev2"
+lvcreate -n $lv3 -l 4 $vg1 "$dev3"
+vgchange -an $vg1
+aux disable_dev "$dev1"
+# (lvm$mdatype) vgreduce --removemissing --force repares to linear
+vgreduce --removemissing --force $vg1
+check lv_field $vg1/$lv1 segtype linear
+check pvlv_counts $vg1 2 3 0
+# cleanup
+aux enable_dev "$dev1"
+pvscan
+vgremove -f $vg1
+not vgs $vg1 # just double-check it's really gone
+
+#COMM "vgreduce rejects --removemissing --mirrorsonly --force when nonmirror lv lost too"
+# (lvm$mdatype) setup: create mirror + linear lvs
+vgcreate -c n -M$mdatype $vg1 $(cat DEVICES)
+lvcreate -n $lv2 -l 4 $vg1
+lvcreate -m1 -n $lv1 -l 4 $vg1 "$dev1" "$dev2" "$dev3"
+lvcreate -n $lv3 -l 4 $vg1 "$dev3"
+pvs --segments -o +lv_name $(cat DEVICES) # for record only
+# (lvm$mdatype) setup: damage one pv
+vgchange -an $vg1
+aux disable_dev "$dev1"
+#pvcreate -ff -y "$dev1"
+# vgreduce rejects --removemissing --mirrorsonly --force when nonmirror lv lost too
+#not vgreduce -c n --removemissing --mirrorsonly --force $vg1
+# CHECKME - command above was rejected becuase of '-c n'
+vgreduce --removemissing --mirrorsonly --force $vg1
+
+aux enable_dev "$dev1"
+
+pvs -P $(cat DEVICES) # for record
+lvs -P $vg1           # for record
+vgs -P $vg1           # for record
diff --git a/test/shell/vgrename-usage.sh b/test/shell/vgrename-usage.sh
new file mode 100644 (file)
index 0000000..2b8ac5a
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/sh
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux prepare_devs 4
+pvcreate "$dev1" "$dev2"
+pvcreate --metadatacopies 0 "$dev3" "$dev4"
+
+# vgrename normal operation - rename vg1 to vg2
+# vgrename normal operation - rename vg2 to vg1
+# ensure name ordering does not matter
+vgcreate $vg1 "$dev1" "$dev2"
+vgrename $vg1 $vg2
+check vg_field $vg2 vg_name $vg2
+vgrename $vg2 $vg1
+check vg_field $vg1 vg_name $vg1
+vgremove $vg1
+
+# vgrename by uuid (bz231187)
+vgcreate $vg1 "$dev1" "$dev3"
+UUID=$(vgs --noheading -o vg_uuid $vg1)
+check vg_field $vg1 vg_uuid $UUID
+vgrename $UUID $vg2
+check vg_field $vg2 vg_name $vg2
+vgremove $vg2
+
+# vgrename fails - new vg already exists
+vgcreate $vg1 "$dev1"
+vgcreate $vg2 "$dev2"
+not vgrename $vg1 $vg2
+vgremove $vg1 $vg2
diff --git a/test/shell/vgsplit-operation.sh b/test/shell/vgsplit-operation.sh
new file mode 100644 (file)
index 0000000..c9cc04a
--- /dev/null
@@ -0,0 +1,294 @@
+#!/bin/sh
+# Copyright (C) 2007 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# Test vgsplit operation, including different LV types
+
+. lib/test
+
+COMM() {
+       LAST_TEST="$@"
+}
+
+create_vg_() {
+       vgcreate -c n -s 64k "$@"
+}
+
+aux prepare_pvs 5 10
+# FIXME: paramaterize lvm1 vs lvm2 metadata; most of these tests should run
+# fine with lvm1 metadata as well; for now, just add disks 5 and 6 as lvm1
+# metadata
+
+#
+# vgsplit can be done into a new or existing VG
+#
+for i in new existing
+do
+       #
+       # We can have PVs or LVs on the cmdline
+       #
+       for j in PV LV
+       do
+COMM "vgsplit correctly splits single linear LV into $i VG ($j args)"
+               create_vg_ $vg1 "$dev1" "$dev2"
+               test $i = existing && create_vg_ $vg2 "$dev3" "$dev4"
+
+               lvcreate -l 4 -n $lv1 $vg1 "$dev1"
+               vgchange -an $vg1
+               if [ $j = PV ]; then
+                 vgsplit $vg1 $vg2 "$dev1"
+               else
+                 vgsplit -n $lv1 $vg1 $vg2
+               fi
+               check pvlv_counts $vg1 1 0 0
+               if [ $i = existing ]; then
+                  check pvlv_counts $vg2 3 1 0
+               else
+                  check pvlv_counts $vg2 1 1 0
+               fi
+               lvremove -f $vg2/$lv1
+               vgremove -f $vg2 $vg1
+
+COMM "vgsplit correctly splits single striped LV into $i VG ($j args)"
+               create_vg_ $vg1 "$dev1" "$dev2"
+               test $i = existing && create_vg_ $vg2 "$dev3" "$dev4"
+
+               lvcreate -l 4 -i 2 -n $lv1 $vg1 "$dev1" "$dev2"
+               vgchange -an $vg1
+               if [ $j = PV ]; then
+                 vgsplit $vg1 $vg2 "$dev1" "$dev2"
+               else
+                 vgsplit -n $lv1 $vg1 $vg2
+               fi
+               if [ $i = existing ]; then
+                 check pvlv_counts $vg2 4 1 0
+               else
+                 check pvlv_counts $vg2 2 1 0
+               fi
+               lvremove -f $vg2/$lv1
+               vgremove -f $vg2
+
+COMM "vgsplit correctly splits mirror LV into $i VG ($j args)"
+               create_vg_ $vg1 "$dev1" "$dev2" "$dev3"
+               test $i = existing && create_vg_ $vg2 "$dev4"
+
+               lvcreate -l 64 -m1 -n $lv1 $vg1 "$dev1" "$dev2" "$dev3"
+               vgchange -an $vg1
+               if [ $j = PV ]; then
+                 vgsplit $vg1 $vg2 "$dev1" "$dev2" "$dev3"
+               else
+                 vgsplit -n $lv1 $vg1 $vg2
+               fi
+               if [ $i = existing ]; then
+                 check pvlv_counts $vg2 4 1 0
+               else
+                 check pvlv_counts $vg2 3 1 0
+               fi
+               lvremove -f $vg2/$lv1
+               vgremove -f $vg2
+# FIXME: ensure split /doesn't/ work when not all devs of mirror specified
+
+COMM "vgsplit correctly splits mirror LV with mirrored log into $i VG ($j args)"
+               create_vg_ $vg1 "$dev1" "$dev2" "$dev3" "$dev4"
+               test $i = existing && create_vg_ $vg2 "$dev5"
+
+               lvcreate -l 64 --mirrorlog mirrored -m1 -n $lv1 $vg1 \
+                   "$dev1" "$dev2" "$dev3" "$dev4"
+
+               vgchange -an $vg1
+               if [ $j = PV ]; then
+                 vgsplit $vg1 $vg2 "$dev1" "$dev2" "$dev3" "$dev4"
+               else
+                 vgsplit -n $lv1 $vg1 $vg2
+               fi
+               if [ $i = existing ]; then
+                 check pvlv_counts $vg2 5 1 0
+               else
+                 check pvlv_counts $vg2 4 1 0
+               fi
+               lvremove -f $vg2/$lv1
+               vgremove -f $vg2
+# FIXME: ensure split /doesn't/ work when not all devs of mirror specified
+
+COMM "vgsplit correctly splits origin and snapshot LV into $i VG ($j args)"
+               create_vg_ $vg1 "$dev1" "$dev2"
+               test $i = existing && create_vg_ $vg2 "$dev3" "$dev4"
+
+               lvcreate -l 64 -i 2 -n $lv1 $vg1 "$dev1" "$dev2"
+               lvcreate -l 4 -i 2 -s -n $lv2 $vg1/$lv1
+               vgchange -an $vg1
+               if [ $j = PV ]; then
+                 vgsplit $vg1 $vg2 "$dev1" "$dev2"
+               else
+                 vgsplit -n $lv1 $vg1 $vg2
+               fi
+               if [ $i = existing ]; then
+                 check pvlv_counts $vg2 4 2 1
+               else
+                 check pvlv_counts $vg2 2 2 1
+               fi
+               lvremove -f $vg2/$lv2
+               lvremove -f $vg2/$lv1
+               vgremove -f $vg2
+
+COMM "vgsplit correctly splits linear LV but not snap+origin LV into $i VG ($j args)"
+               create_vg_ $vg1 "$dev1" "$dev2"
+               test $i = existing && create_vg_ $vg2 "$dev3"
+
+               lvcreate -l 64 -i 2 -n $lv1 $vg1
+               lvcreate -l 4 -i 2 -s -n $lv2 $vg1/$lv1
+               vgextend $vg1 "$dev4"
+               lvcreate -l 64 -n $lv3 $vg1 "$dev4"
+               vgchange -an $vg1
+               if [ $j = PV ]; then
+                 vgsplit $vg1 $vg2 "$dev4"
+               else
+                 vgsplit -n $lv3 $vg1 $vg2
+               fi
+               if [ $i = existing ]; then
+                 check pvlv_counts $vg2 2 1 0
+                 check pvlv_counts $vg1 2 2 1
+               else
+                 check pvlv_counts $vg2 1 1 0
+                 check pvlv_counts $vg1 2 2 1
+               fi
+               lvremove -f $vg1/$lv2
+               lvremove -f $vg1/$lv1 $vg2/$lv3
+               vgremove -f $vg1 $vg2
+
+COMM "vgsplit correctly splits linear LV but not mirror LV into $i VG ($j args)"
+               create_vg_ $vg1 "$dev1" "$dev2" "$dev3"
+               test $i = existing && create_vg_ $vg2 "$dev5"
+
+               lvcreate -l 64 -m1 -n $lv1 $vg1 "$dev1" "$dev2" "$dev3"
+               vgextend $vg1 "$dev4"
+               lvcreate -l 64 -n $lv2 $vg1 "$dev4"
+               vgchange -an $vg1
+               if [ $j = PV ]; then
+                 vgsplit $vg1 $vg2 "$dev4"
+               else
+                 vgsplit -n $lv2 $vg1 $vg2
+               fi
+               if [ $i = existing ]; then
+                 check pvlv_counts $vg1 3 1 0
+                 check pvlv_counts $vg2 2 1 0
+               else
+                 check pvlv_counts $vg1 3 1 0
+                 check pvlv_counts $vg2 1 1 0
+               fi
+               vgremove -f $vg1 $vg2
+
+       done
+done
+
+#
+# Test more complex setups where the code has to find associated PVs and
+# LVs to split the VG correctly
+#
+COMM "vgsplit fails splitting 3 striped LVs into VG when only 1 LV specified"
+create_vg_ $vg1 "$dev1" "$dev2" "$dev3" "$dev4"
+lvcreate -l 4 -n $lv1 -i 2 $vg1 "$dev1" "$dev2"
+lvcreate -l 4 -n $lv2 -i 2 $vg1 "$dev2" "$dev3"
+lvcreate -l 4 -n $lv3 -i 2 $vg1 "$dev3" "$dev4"
+vgchange -an $vg1
+not vgsplit -n $lv1 $vg1 $vg2
+vgremove -f $vg1
+
+COMM "vgsplit fails splitting one LV with 2 snapshots, only origin LV specified"
+create_vg_ $vg1 "$dev1" "$dev2" "$dev3" "$dev4"
+lvcreate -l 16 -n $lv1 $vg1 "$dev1" "$dev2"
+lvcreate -l 4 -n $lv2 -s $vg1/$lv1 "$dev3"
+lvcreate -l 4 -n $lv3 -s $vg1/$lv1 "$dev4"
+check pvlv_counts $vg1 4 3 2
+vgchange -an $vg1
+not vgsplit -n $lv1 $vg1 $vg2;
+lvremove -f $vg1/$lv2 $vg1/$lv3
+lvremove -f $vg1/$lv1
+vgremove -f $vg1
+
+COMM "vgsplit fails splitting one LV with 2 snapshots, only snapshot LV specified"
+create_vg_ $vg1 "$dev1" "$dev2" "$dev3" "$dev4"
+lvcreate -l 16 -n $lv1 $vg1 "$dev1" "$dev2"
+lvcreate -l 4 -n $lv2 -s $vg1/$lv1 "$dev3"
+lvcreate -l 4 -n $lv3 -s $vg1/$lv1 "$dev4"
+check pvlv_counts $vg1 4 3 2
+vgchange -an $vg1
+not vgsplit -n $lv2 $vg1 $vg2
+lvremove -f $vg1/$lv2 $vg1/$lv3
+lvremove -f $vg1/$lv1
+vgremove -f $vg1
+
+COMM "vgsplit fails splitting one mirror LV, only one PV specified"
+create_vg_ $vg1 "$dev1" "$dev2" "$dev3" "$dev4"
+lvcreate -l 16 -n $lv1 -m1 $vg1 "$dev1" "$dev2" "$dev3"
+check pvlv_counts $vg1 4 1 0
+vgchange -an $vg1
+not vgsplit $vg1 $vg2 "$dev2"
+vgremove -ff $vg1
+
+COMM "vgsplit fails splitting 1 mirror + 1 striped LV, only striped LV specified"
+create_vg_ $vg1 "$dev1" "$dev2" "$dev3" "$dev4"
+lvcreate -l 16 -n $lv1 -m1 $vg1 "$dev1" "$dev2" "$dev3"
+lvcreate -l 16 -n $lv2 -i 2 $vg1 "$dev3" "$dev4"
+check pvlv_counts $vg1 4 2 0
+vgchange -an $vg1
+not vgsplit -n $lv2 $vg1 $vg2 2>err
+vgremove -f $vg1
+
+#
+# Verify vgsplit rejects active LVs only when active LVs involved in split
+#
+COMM "vgsplit fails, active mirror involved in split"
+create_vg_ $vg1 "$dev1" "$dev2" "$dev3" "$dev4"
+lvcreate -l 16 -n $lv1 -m1 $vg1 "$dev1" "$dev2" "$dev3"
+lvcreate -l 16 -n $lv2 $vg1 "$dev4"
+lvchange -an $vg1/$lv2
+check pvlv_counts $vg1 4 2 0
+not vgsplit -n $lv1 $vg1 $vg2;
+check pvlv_counts $vg1 4 2 0
+vgremove -f $vg1
+
+COMM "vgsplit succeeds, active mirror not involved in split"
+create_vg_ $vg1 "$dev1" "$dev2" "$dev3" "$dev4"
+lvcreate -l 16 -n $lv1 -m1 $vg1 "$dev1" "$dev2" "$dev3"
+lvcreate -l 16 -n $lv2 $vg1 "$dev4"
+lvchange -an $vg1/$lv2
+check pvlv_counts $vg1 4 2 0
+vgsplit -n $lv2 $vg1 $vg2
+check pvlv_counts $vg1 3 1 0
+check pvlv_counts $vg2 1 1 0
+vgremove -f $vg1 $vg2
+
+COMM "vgsplit fails, active snapshot involved in split"
+create_vg_ $vg1 "$dev1" "$dev2" "$dev3" "$dev4"
+lvcreate -l 64 -i 2 -n $lv1 $vg1 "$dev1" "$dev2"
+lvcreate -l 4 -i 2 -s -n $lv2 $vg1/$lv1
+lvcreate -l 64 -i 2 -n $lv3 $vg1 "$dev3" "$dev4"
+lvchange -an $vg1/$lv3
+check pvlv_counts $vg1 4 3 1
+not vgsplit -n $lv2 $vg1 $vg2;
+check pvlv_counts $vg1 4 3 1
+lvremove -f $vg1/$lv2
+vgremove -f $vg1
+
+COMM "vgsplit succeeds, active snapshot not involved in split"
+create_vg_ $vg1 "$dev1" "$dev2" "$dev3"
+lvcreate -l 64 -i 2 -n $lv1 $vg1 "$dev1" "$dev2"
+lvcreate -l 4 -s -n $lv2 $vg1/$lv1
+vgextend $vg1 "$dev4"
+lvcreate -l 64 -n $lv3 $vg1 "$dev4"
+lvchange -an $vg1/$lv3
+check pvlv_counts $vg1 4 3 1
+vgsplit -n $lv3 $vg1 $vg2
+check pvlv_counts $vg1 3 2 1
+check pvlv_counts $vg2 1 1 0
+vgchange -an $vg1
+lvremove -f $vg1/$lv2
+vgremove -f $vg1 $vg2
diff --git a/test/shell/vgsplit-stacked.sh b/test/shell/vgsplit-stacked.sh
new file mode 100644 (file)
index 0000000..62a5304
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+. lib/test
+
+aux lvmconf 'devices/filter = [ "a/dev\/mirror/", "a/dev\/mapper\/.*$/", "a/dev\/LVMTEST/", "r/.*/" ]'
+aux prepare_pvs 3
+
+vgcreate $vg1 "$dev1" "$dev2"
+lvcreate -n $lv1 -l 100%FREE $vg1
+
+#top VG
+pvcreate $DM_DEV_DIR/$vg1/$lv1
+vgcreate $vg $DM_DEV_DIR/$vg1/$lv1 "$dev3"
+
+vgchange -a n $vg $vg1
+
+# this should fail but not segfault, RHBZ 481793.
+not vgsplit $vg $vg1 "$dev3"
diff --git a/test/shell/vgsplit-usage.sh b/test/shell/vgsplit-usage.sh
new file mode 100644 (file)
index 0000000..10167d7
--- /dev/null
@@ -0,0 +1,168 @@
+#!/bin/sh
+# Copyright (C) 2007-2011 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+# Test vgsplit command options for validity
+
+. lib/test
+
+aux prepare_devs 5
+
+for mdatype in 1 2
+do
+
+pvcreate -M$mdatype $(cat DEVICES)
+
+# ensure name order does not matter
+# NOTE: if we're using lvm1, we must use -M on vgsplit
+vgcreate -M$mdatype $vg1 $(cat DEVICES)
+vgsplit -M$mdatype $vg1 $vg2 "$dev1"
+vgremove $vg1 $vg2
+
+vgcreate -M$mdatype $vg2 $(cat DEVICES)
+vgsplit -M$mdatype $vg2 $vg1 "$dev1"
+vgremove $vg1 $vg2
+
+# vgsplit accepts new vg as destination of split
+# lvm1 -- bz244792
+vgcreate -M$mdatype $vg1 $(cat DEVICES)
+vgsplit $vg1 $vg2 "$dev1" 1>err
+grep "New volume group \"$vg2\" successfully split from \"$vg1\"" err
+vgremove $vg1 $vg2
+
+# vgsplit accepts existing vg as destination of split
+vgcreate -M$mdatype $vg1 "$dev1" "$dev2"
+vgcreate -M$mdatype $vg2 "$dev3" "$dev4"
+vgsplit $vg1 $vg2 "$dev1" 1>err
+grep "Existing volume group \"$vg2\" successfully split from \"$vg1\"" err
+vgremove $vg1 $vg2
+
+# vgsplit accepts --maxphysicalvolumes 128 on new VG
+vgcreate -M$mdatype $vg1 "$dev1" "$dev2"
+vgsplit --maxphysicalvolumes 128 $vg1 $vg2 "$dev1"
+check vg_field $vg2 max_pv 128
+vgremove $vg1 $vg2
+
+# vgsplit accepts --maxlogicalvolumes 128 on new VG
+vgcreate -M$mdatype $vg1 "$dev1" "$dev2"
+vgsplit --maxlogicalvolumes 128 $vg1 $vg2 "$dev1"
+check vg_field $vg2 max_lv 128
+vgremove $vg1 $vg2
+
+# vgsplit rejects split because max_pv of destination would be exceeded
+vgcreate -M$mdatype --maxphysicalvolumes 2 $vg1 "$dev1" "$dev2"
+vgcreate -M$mdatype --maxphysicalvolumes 2 $vg2 "$dev3" "$dev4"
+not vgsplit $vg1 $vg2 "$dev1" 2>err;
+grep "Maximum number of physical volumes (2) exceeded" err
+vgremove $vg1 $vg2
+
+# vgsplit rejects split because maxphysicalvolumes given with existing vg
+vgcreate -M$mdatype --maxphysicalvolumes 2 $vg1 "$dev1" "$dev2"
+vgcreate -M$mdatype --maxphysicalvolumes 2 $vg2 "$dev3" "$dev4"
+not vgsplit --maxphysicalvolumes 2 $vg1 $vg2 "$dev1" 2>err;
+grep "Volume group \"$vg2\" exists, but new VG option specified" err
+vgremove $vg1 $vg2
+
+# vgsplit rejects split because maxlogicalvolumes given with existing vg
+vgcreate -M$mdatype --maxlogicalvolumes 2 $vg1 "$dev1" "$dev2"
+vgcreate -M$mdatype --maxlogicalvolumes 2 $vg2 "$dev3" "$dev4"
+not vgsplit --maxlogicalvolumes 2 $vg1 $vg2 "$dev1" 2>err
+grep "Volume group \"$vg2\" exists, but new VG option specified" err
+vgremove $vg1 $vg2
+
+# vgsplit rejects split because alloc given with existing vg
+vgcreate -M$mdatype --alloc cling $vg1 "$dev1" "$dev2"
+vgcreate -M$mdatype --alloc cling $vg2 "$dev3" "$dev4"
+not vgsplit --alloc cling $vg1 $vg2 "$dev1" 2>err;
+grep "Volume group \"$vg2\" exists, but new VG option specified" err
+vgremove $vg1 $vg2
+
+# vgsplit rejects split because clustered given with existing vg
+vgcreate -M$mdatype --clustered n $vg1 "$dev1" "$dev2"
+vgcreate -M$mdatype --clustered n $vg2 "$dev3" "$dev4"
+not vgsplit --clustered n $vg1 $vg2 "$dev1" 2>err
+grep "Volume group \"$vg2\" exists, but new VG option specified" err
+vgremove $vg1 $vg2
+
+# vgsplit rejects vg with active lv
+pvcreate -M$mdatype -ff "$dev3" "$dev4"
+vgcreate -M$mdatype $vg1 "$dev1" "$dev2"
+vgcreate -M$mdatype $vg2 "$dev3" "$dev4"
+lvcreate -l 4 -n $lv1 $vg1
+not vgsplit $vg1 $vg2 "$dev1" 2>err;
+grep "Logical volumes in \"$vg1\" must be inactive\$" err
+vgremove -f $vg1 $vg2
+
+# vgsplit rejects split because max_lv is exceeded
+vgcreate -M$mdatype --maxlogicalvolumes 2 $vg1 "$dev1" "$dev2"
+vgcreate -M$mdatype --maxlogicalvolumes 2 $vg2 "$dev3" "$dev4"
+lvcreate -l 4 -n $lv1 $vg1
+lvcreate -l 4 -n $lv2 $vg1
+lvcreate -l 4 -n $lv3 $vg2
+vgchange -an $vg1 $vg2
+not vgsplit $vg1 $vg2 "$dev1" 2>err;
+grep "Maximum number of logical volumes (2) exceeded" err
+vgremove -f $vg1 $vg2
+
+# vgsplit verify default - max_lv attribute from new VG is same as source VG" \
+vgcreate -M$mdatype $vg1 "$dev1" "$dev2"
+lvcreate -l 4 -n $lv1 $vg1
+vgchange -an $vg1
+vgsplit $vg1 $vg2 "$dev1"
+check compare_vg_field $vg1 $vg2 max_lv
+vgremove -f $vg1 $vg2
+
+# vgsplit verify default - max_pv attribute from new VG is same as source VG" \
+vgcreate -M$mdatype $vg1 "$dev1" "$dev2"
+lvcreate -l 4 -n $lv1 $vg1
+vgchange -an $vg1
+vgsplit $vg1 $vg2 "$dev1"
+check compare_vg_field $vg1 $vg2 max_pv
+vgremove -f $vg1 $vg2
+
+# vgsplit verify default - vg_fmt attribute from new VG is same as source VG" \
+vgcreate -M$mdatype $vg1 "$dev1" "$dev2"
+lvcreate -l 4 -n $lv1 $vg1
+vgchange -an $vg1
+vgsplit $vg1 $vg2 "$dev1"
+check compare_vg_field $vg1 $vg2 vg_fmt
+vgremove -f $vg2 $vg1
+
+# vgsplit rejects split because PV not in VG
+vgcreate -M$mdatype $vg1 "$dev1" "$dev2"
+vgcreate -M$mdatype $vg2 "$dev3" "$dev4"
+lvcreate -l 4 -n $lv1 $vg1
+lvcreate -l 4 -n $lv2 $vg1
+vgchange -an $vg1
+not vgsplit $vg1 $vg2 "$dev3" 2>err;
+vgremove -f $vg2 $vg1
+done
+
+# ONLY LVM2 metadata
+# setup PVs" '
+pvcreate --metadatacopies 0 "$dev5"
+
+# vgsplit rejects to give away pv with the last mda copy
+vgcreate $vg1 "$dev5" "$dev2"
+lvcreate -l 10 -n $lv1  $vg1
+lvchange -an $vg1/$lv1
+check pvlv_counts $vg1 2 1 0
+not vgsplit  $vg1 $vg2 "$dev5";
+check pvlv_counts $vg1 2 1 0
+vgremove -f $vg1
+
+# vgsplit rejects split because metadata types differ
+pvcreate -ff -M1 "$dev3" "$dev4"
+pvcreate -ff "$dev1" "$dev2"
+vgcreate -M1 $vg1 "$dev3" "$dev4"
+vgcreate $vg2 "$dev1" "$dev2"
+not vgsplit $vg1 $vg2 "$dev3" 2>err;
+grep "Metadata types differ" err
+vgremove -f $vg1 $vg2
diff --git a/test/t-000-basic.sh b/test/t-000-basic.sh
deleted file mode 100755 (executable)
index ed76a6f..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 2009 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-lvm version
-
-v=$abs_top_srcdir/lib/misc/lvm-version.h
-sed -n "/#define LVM_VERSION ./s///p" "$v" | sed "s/ .*//" > expected
-
-lvm pvmove --version|sed -n "1s/.*: *\([0-9][^ ]*\) .*/\1/p" > actual
-
-# ensure they are the same
-diff -u actual expected
-
-mknod $DM_DEV_DIR/null c 1 3 || \
-  error "Can't create nodes on filesystem"
-echo >$DM_DEV_DIR/null || \
-  error "Filesystem for tests does not allow using device nodes (check nodev)"
-
-# ensure we can create devices (uses dmsetup, etc)
-aux prepare_devs 5
-
diff --git a/test/t-activate-missing.sh b/test/t-activate-missing.sh
deleted file mode 100644 (file)
index 4242f21..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-#!/bin/bash
-
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-# Test activation behaviour with devices missing.
-# - snapshots and their origins are only activated together; if one fails, both
-#   fail
-# - partial mirrors are not activated (but maybe they should? maybe we should
-#   instead lvconvert --repair them?)
-# - linear LVs with bits missing are not activated
-
-. ./test-utils.sh
-
-prepare_vg 4
-
-lvcreate -l1 -n linear1 $vg $dev1
-lvcreate -l1 -n linear2 $vg $dev2
-lvcreate -l2 -n linear12 $vg $dev1:4 $dev2:4
-
-lvcreate -l1 -n origin1 $vg $dev1
-lvcreate -s $vg/origin1 -l1 -n s_napshot2 $dev2
-
-lvcreate -l1 -m1 -n mirror12 --mirrorlog core $vg $dev1 $dev2
-lvcreate -l1 -m1 -n mirror123 $vg $dev1 $dev2 $dev3
-
-vgchange -a n $vg
-disable_dev $dev1
-not vgchange -a y $vg
-not vgck $vg
-
-check inactive $vg linear1
-check active $vg linear2
-check inactive $vg origin1
-check inactive $vg s_napshot2
-check inactive $vg linear12
-check inactive $vg mirror12
-check inactive $vg mirror123
-
-vgchange -a n $vg
-enable_dev $dev1
-disable_dev $dev2
-not vgchange -a y $vg
-not vgck $vg
-
-check active $vg linear1
-check inactive $vg linear2
-check inactive $vg linear12
-check inactive $vg origin1
-check inactive $vg s_napshot2
-check inactive $vg mirror12
-check inactive $vg mirror123
-
-vgchange -a n $vg
-enable_dev $dev2
-disable_dev $dev3
-not vgchange -a y $vg
-not vgck $vg
-
-check active $vg origin1
-check active $vg s_napshot2
-check active $vg linear1
-check active $vg linear2
-check active $vg linear12
-check inactive $vg mirror123
-check active $vg mirror12
-
-vgchange -a n $vg
-enable_dev $dev3
-disable_dev $dev4
-vgchange -a y $vg
-not vgck $vg
-
-check active $vg origin1
-check active $vg s_napshot2
-check active $vg linear1
-check active $vg linear2
-check active $vg linear12
-check active $vg mirror12
-check active $vg mirror123
diff --git a/test/t-activate-partial.sh b/test/t-activate-partial.sh
deleted file mode 100644 (file)
index b6bf9cb..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-aux prepare_vg 3
-
-lvcreate -m 1 -l 1 -n mirror $vg
-lvchange -a n $vg/mirror
-disable_dev $dev1
-
-not vgreduce --removemissing $vg
-not lvchange -v -a y $vg/mirror
-lvchange -v --partial -a y $vg/mirror
-not lvchange -v --refresh $vg/mirror
-lvchange -v --refresh --partial $vg/mirror
-
-# also check that vgchange works
-vgchange -a n --partial $vg
-vgchange -a y --partial $vg
-
-# check vgremove
-vgremove -f $vg
diff --git a/test/t-covercmd.sh b/test/t-covercmd.sh
deleted file mode 100755 (executable)
index 358a93e..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-#
-# tests basic functionality of read-ahead and ra regressions
-#
-
-. ./test-utils.sh
-
-TEST_UUID="aaaaaa-aaaa-aaaa-aaaa-aaaa-aaaa-aaaaaa"
-
-get_lvs_()
-{
-  case $(lvs --units s --nosuffix --noheadings -o $1_read_ahead "$vg"/"$lv") in
-    *$2) true ;;
-    *) false ;;
-  esac
-}
-
-aux prepare_devs 5
-
-pvcreate $dev1
-pvcreate --metadatacopies 0 $dev2
-pvcreate --metadatacopies 0 $dev3
-pvcreate $dev4
-pvcreate --norestorefile -u $TEST_UUID --metadatacopies 0 $dev5
-vgcreate -c n $vg $devs
-lvcreate -n $lv -l 5 -i5 -I256 $vg
-
-# test *scan and *display tools
-pvscan
-vgscan
-lvscan
-lvmdiskscan
-vgdisplay --units k
-lvdisplay --units g
-for i in h b s k m g t p e H B S K M G T P E ; do
-    pvdisplay --units "$i" "$dev1"
-done
-
-# test vgexport vgimport tools
-vgchange -an $vg
-vgexport $vg
-vgimport $vg
-vgchange -ay $vg
-
-# "-persistent y --major 254 --minor 20"
-# "-persistent n"
-# test various lvm utils
-for i in dumpconfig formats segtypes; do
-    lvm "$i"
-done
-
-for i in pr "p rw" an ay "-monitor y" "-monitor n" \
-        -resync -refresh "-addtag MYTAG" "-deltag MYETAG"; do
-    lvchange -$i "$vg"/"$lv"
-done
-
-pvck "$dev1"
-vgck "$vg"
-lvrename "$vg" "$lv" "$lv-rename"
-vgcfgbackup -f "$(pwd)/backup.$$" "$vg"
-vgchange -an "$vg"
-vgcfgrestore  -f "$(pwd)/backup.$$" "$vg"
-pvremove -y -ff $dev5
-not vgcfgrestore  -f "$(pwd)/backup.$$" "$vg"
-pvcreate -u $TEST_UUID --restorefile  "$(pwd)/backup.$$" $dev5
-vgremove -f "$vg"
-pvresize --setphysicalvolumesize 10M "$dev1"
-
-# test various errors and obsoleted tools
-not lvmchange
-not lvrename "$vg"
-not lvrename "$vg-xxx"
-not lvrename "$vg"  "$vg"/"$lv-rename" "$vg"/"$lv"
diff --git a/test/t-dmeventd-restart.sh b/test/t-dmeventd-restart.sh
deleted file mode 100644 (file)
index 6368d77..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-prepare_vg 5
-prepare_dmeventd
-
-which mkfs.ext2 || exit 200
-
-lvcreate -m 3 --ig -L 1 -n 4way $vg
-lvchange --monitor y $vg/4way
-lvcreate -m 2 --ig -L 1 -n 3way $vg
-lvchange --monitor y $vg/3way
-
-dmeventd -R -f &
-LOCAL_DMEVENTD="$!"
-
-sleep 1 # wait a bit, so we talk to the new dmeventd later
-
-lvchange --monitor y --verbose $vg/3way 2>&1 | tee lvchange.out
-grep 'already monitored' lvchange.out
-lvchange --monitor y --verbose $vg/4way 2>&1 | tee lvchange.out
-grep 'already monitored' lvchange.out
diff --git a/test/t-fsadm.sh b/test/t-fsadm.sh
deleted file mode 100644 (file)
index 17d2090..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2008-2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-test_description='Exercise fsadm filesystem resize'
-exit 200
-
-. ./test-utils.sh
-
-aux prepare_vg 1 100
-
-# set to "skip" to avoid testing given fs and test warning result
-# i.e. check_reiserfs=skip
-check_ext3=
-check_xfs=
-check_reiserfs=
-
-which mkfs.ext3 || check_ext3=${check_ext3:=mkfs.ext3}
-which fsck.ext3 || check_ext3=${check_ext3:=fsck.ext3}
-which mkfs.xfs || check_xfs=${check_xfs:=mkfs.xfs}
-which xfs_check || check_xfs=${check_xfs:=xfs_check}
-which mkfs.reiserfs || check_reiserfs=${check_reiserfs:=mkfs.reiserfs}
-which reiserfsck || check_reiserfs=${check_reiserfs:=reiserfsck}
-
-vg_lv="$vg/$lv1"
-dev_vg_lv="$DM_DEV_DIR/$vg_lv"
-mount_dir="$TESTDIR/mnt"
-
-test ! -d $mount_dir && mkdir $mount_dir
-
-cleanup_mounted_and_teardown()
-{
-       umount $mount_dir || true
-       teardown
-}
-
-fscheck_ext3()
-{
-       fsck.ext3 -p -F -f $dev_vg_lv
-}
-
-fscheck_xfs()
-{
-       xfs_check $dev_vg_lv
-}
-
-fscheck_reiserfs()
-{
-       reiserfsck --check -p -f $dev_vg_lv </dev/null
-}
-
-check_missing()
-{
-       eval local t=$\check_$1
-       test -z "$t" && return 0
-       test "$t" = skip && return 1
-       # trick for warning test
-       echo "TEST ""WARNING: fsadm skips $1 tests, $t tool is missing"
-       return 1
-}
-
-# Test for block sizes != 1024 (rhbz #480022)
-lvcreate -n $lv1 -L20M $vg
-trap 'aux cleanup_mounted_and_teardown' EXIT
-
-if check_missing ext3; then
-       mkfs.ext3 -b4096 -j $dev_vg_lv
-
-       fsadm --lvresize resize $vg_lv 30M
-       # Fails - not enough space for 4M fs
-       not fsadm --lvresize resize $dev_vg_lv 4M
-       lvresize -L+10M -r $vg_lv
-       lvreduce -L10M -r $vg_lv
-
-       fscheck_ext3
-       mount $dev_vg_lv $mount_dir
-       not fsadm --lvresize resize $vg_lv 9M
-       lvresize -L+20M -r -n $vg_lv
-       umount $mount_dir
-       fscheck_ext3
-
-       lvresize -f -L20M $vg_lv
-fi
-
-if check_missing xfs; then
-       mkfs.xfs -l internal,size=1000b -f $dev_vg_lv
-
-       fsadm --lvresize resize $vg_lv 30M
-       # Fails - not enough space for 4M fs
-       lvresize -L+10M -r $vg_lv
-       not lvreduce -L10M -r $vg_lv
-
-       fscheck_xfs
-       mount $dev_vg_lv $mount_dir
-       lvresize -L+10M -r -n $vg_lv
-       umount $mount_dir
-       fscheck_xfs
-
-       lvresize -f -L20M $vg_lv
-fi
-
-if check_missing reiserfs; then
-       mkfs.reiserfs -s 513 -f $dev_vg_lv
-
-       fsadm --lvresize resize $vg_lv 30M
-       lvresize -L+10M -r $vg_lv
-       fsadm --lvresize -y resize $vg_lv 10M
-
-       fscheck_reiserfs
-       mount $dev_vg_lv $mount_dir
-
-       not fsadm -y --lvresize resize $vg_lv 20M
-       umount $mount_dir
-
-       lvresize -f -L20M $vg_lv
-fi
diff --git a/test/t-inconsistent-metadata.sh b/test/t-inconsistent-metadata.sh
deleted file mode 100644 (file)
index 310dde5..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-aux prepare_vg 3
-
-lvcreate -m 1 -l 1 -n mirror $vg
-lvcreate -l 1 -n resized $vg
-lvchange -a n $vg/mirror
-
-backup_dev $devs
-
-init() {
-       restore_dev $devs
-       lvs -o lv_name,lv_size --units k $vg | tee lvs.out
-       grep resized lvs.out | not grep 8192
-       lvresize -L 8192K $vg/resized
-       restore_dev $dev1
-}
-
-check() {
-       lvs -o lv_name,lv_size --units k $vg | tee lvs.out
-       grep resized lvs.out | grep 8192
-}
-
-# vgscan fixes up metadata
-init
-vgscan 2>&1 | tee cmd.out
-grep "Inconsistent metadata found for VG $vg" cmd.out
-vgscan 2>&1 | tee cmd.out
-not grep "Inconsistent metadata found for VG $vg" cmd.out
-check
-
-# vgdisplay fixes
-init
-vgdisplay 2>&1 | tee cmd.out
-grep "Inconsistent metadata found for VG $vg" cmd.out
-vgdisplay 2>&1 | tee cmd.out
-not grep "Inconsistent metadata found for VG $vg" cmd.out
-check
-
-# lvs fixes up
-init
-lvs 2>&1 | tee cmd.out
-grep "Inconsistent metadata found for VG $vg" cmd.out
-vgdisplay 2>&1 | tee cmd.out
-not grep "Inconsistent metadata found for VG $vg" cmd.out
-check
-
-# vgs fixes up as well
-init
-vgs 2>&1 | tee cmd.out
-grep "Inconsistent metadata found for VG $vg" cmd.out
-vgs 2>&1 | tee cmd.out
-not grep "Inconsistent metadata found for VG $vg" cmd.out
-check
-
-echo Check auto-repair of failed vgextend - metadata written to original pv but not new pv
-vgremove -f $vg
-pvremove -ff $devs
-pvcreate $devs
-backup_dev $dev2
-vgcreate $vg $dev1
-vgextend $vg $dev2
-restore_dev $dev2
-should compare_two_fields_ vgs $vg vg_mda_count pvs $dev2 vg_mda_count
diff --git a/test/t-listings.sh b/test/t-listings.sh
deleted file mode 100644 (file)
index 9ea10b6..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-#
-# tests functionality of lvs, pvs, vgs, *display tools
-#
-
-. ./test-utils.sh
-
-get_lvs_()
-{
-  case $(lvs --units s --nosuffix --noheadings -o $1_read_ahead "$vg"/"$lv") in
-    *$2) true ;;
-    *) false ;;
-  esac
-}
-
-aux prepare_devs 5
-
-pvcreate $dev1
-pvcreate --metadatacopies 0 $dev2
-pvcreate --metadatacopies 0 $dev3
-pvcreate $dev4
-pvcreate --metadatacopies 0 $dev5
-
-#COMM bz195276 -- pvs doesn't show PVs until a VG is created
-pvs --noheadings|tee out
-test $(wc -l <out) -eq 5
-
-#COMM pvs with segment attributes works even for orphans
-pvs --noheadings -o  seg_all,pv_all,lv_all,vg_all | tee out
-test $(wc -l <out) -eq 5
-
-vgcreate -c n $vg $devs
-
-#COMM pvs and vgs report mda_count, mda_free (bz202886, bz247444)
-pvs -o +pv_mda_count,pv_mda_free $devs
-for I in $dev2 $dev3 $dev5; do
-       aux check_pv_field_ $I pv_mda_count 0
-       aux check_pv_field_ $I pv_mda_free 0
-done
-vgs -o +vg_mda_count,vg_mda_free $vg
-aux check_vg_field_ $vg vg_mda_count 2
-
-#COMM pvs doesn't display --metadatacopies 0 PVs as orphans (bz409061)
-pvdisplay $dev2|grep "VG Name.*$vg"
-test $(pvs -o vg_name --noheadings $dev2) = $vg
-
-#COMM lvs displays snapshots (bz171215)
-lvcreate -l4 -n $lv1 $vg
-lvcreate -l4 -s -n $lv2 $vg/$lv1
-lvs $vg --noheadings|tee out
-test $(wc -l <out) -eq 2
-lvs -a --noheadings|tee out
-# should lvs -a display cow && real devices? (it doesn't)
-test $(wc -l <out) -eq 2
-dmsetup ls|grep $PREFIX|grep -v "LVMTEST.*pv."
-lvremove -f $vg/$lv2
-
-#COMM lvs -a displays mirror legs and log
-lvcreate -l4  -m2 -n$lv3 $vg
-lvs $vg --noheadings|tee out
-test $(wc -l <out) -eq 2
-lvs -a --noheadings|tee out
-test $(wc -l <out) -eq 6
-dmsetup ls|grep $PREFIX|grep -v "LVMTEST.*pv."
-
-#COMM vgs with options from pvs still treats arguments as VGs (bz193543)
-vgs -o pv_name,vg_name $vg
-# would complain if not
-
-#COMM pvdisplay --maps feature (bz149814)
-pvdisplay $devs >out
-pvdisplay --maps $devs >out2
-not diff out out2
-
diff --git a/test/t-lock-blocking.sh b/test/t-lock-blocking.sh
deleted file mode 100644 (file)
index 166340c..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-test_description='test some blocking / non-blocking multi-vg operations'
-
-. ./test-utils.sh
-
-aux prepare_devs 3
-test -n "$LOCAL_CLVMD" && exit 200
-pvcreate $dev1 $dev2
-vgcreate $vg $dev1 $dev2
-
-# if wait_for_locks set, vgremove should wait for orphan lock
-# flock process should have exited by the time first vgremove completes
-flock -w 5 $TESTDIR/var/lock/lvm/P_orphans -c "sleep 10" &
-flock_pid=`jobs -p`
-vgremove --config 'global { wait_for_locks = 1 }' $vg
-not vgremove --config 'global { wait_for_locks = 1 }' $vg
-not ps $flock_pid # finished
-
-# if wait_for_locks not set, vgremove should fail on non-blocking lock
-# we must wait for flock process at the end - vgremove won't wait
-vgcreate $vg $dev1 $dev2
-flock -w 5 $TESTDIR/var/lock/lvm/P_orphans -c "sleep 10" &
-flock_pid=`jobs -p`
-not vgremove --config 'global { wait_for_locks = 0 }' $vg
-ps $flock_pid # still running
-kill $flock_pid
diff --git a/test/t-lvchange-mirror.sh b/test/t-lvchange-mirror.sh
deleted file mode 100644 (file)
index 7c915be..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-aux prepare_vg 3
-
-# force resync 2-way active mirror
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev3:0-1
-check mirror $vg $lv1 $dev3
-echo y | lvchange --resync $vg/$lv1
-check mirror $vg $lv1 $dev3
-lvremove -ff $vg
-
-# force resync 2-way inactive mirror
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev3:0-1
-lvchange -an $vg/$lv1
-check mirror $vg $lv1 $dev3
-lvchange --resync $vg/$lv1
-check mirror $vg $lv1 $dev3
-lvremove -ff $vg
diff --git a/test/t-lvconvert-mirror-basic-0.sh b/test/t-lvconvert-mirror-basic-0.sh
deleted file mode 100644 (file)
index eec6d5c..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./t-lvconvert-mirror-basic.sh
-test_many 0
diff --git a/test/t-lvconvert-mirror-basic-1.sh b/test/t-lvconvert-mirror-basic-1.sh
deleted file mode 100644 (file)
index 7019dbb..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./t-lvconvert-mirror-basic.sh
-test_many 1
diff --git a/test/t-lvconvert-mirror-basic-2.sh b/test/t-lvconvert-mirror-basic-2.sh
deleted file mode 100644 (file)
index 85d54c9..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./t-lvconvert-mirror-basic.sh
-test_many 2
diff --git a/test/t-lvconvert-mirror-basic-3.sh b/test/t-lvconvert-mirror-basic-3.sh
deleted file mode 100644 (file)
index 0c57580..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./t-lvconvert-mirror-basic.sh
-test_many 3
diff --git a/test/t-lvconvert-mirror-basic.sh b/test/t-lvconvert-mirror-basic.sh
deleted file mode 100644 (file)
index 880bd09..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-log_name_to_count()
-{
-       if [ "$1" = "mirrored" ]; then
-               echo 2
-       elif [ "$1" = "disk" ]; then
-               echo 1
-       else
-               echo 0
-       fi
-}
-
-# FIXME: For test_[up|down]convert, I'd still like to be able
-# to specifiy devices - especially if I can do partial PV
-# specification for down-converts.  It may even be wise to
-# do one round through these tests without specifying the PVs
-# to use and one round where we do.
-
-# test_lvconvert
-#   start_mirror_count:  The '-m' argument to create with
-#   start_log_type: core|disk|mirrored
-#   final_mirror_count: The '-m' argument to convert to
-#   final_log_type: core|disk|mirrored
-#   active: Whether the LV should be active when the convert happens
-#
-# Exmaple: Convert 3-way disk-log mirror to
-#          2-way disk-log mirror while not active
-# -> test_lvconvert 2 disk 3 disk 0
-
-test_lvconvert()
-{
-       local start_count=$1
-       local start_count_p1=$(($start_count + 1))
-       local start_log_type=$2
-       local finish_count=$3
-       local finish_count_p1=$(($finish_count + 1))
-       local finish_log_type=$4
-       local dev_array=($dev1 $dev2 $dev3 $dev4 $dev5)
-       local start_log_count
-       local finish_log_count
-       local max_log_count
-       local alloc=""
-       local active=true
-       local i
-
-       if [ "$start_log_type" = "disk" ] &&
-               [ "$finish_log_type" = "mirrored" ]; then
-               echo "FIXME:  disk -> mirrored log conversion not yet supported by LVM"
-               return 0
-       fi
-
-       test "$5" = "active" && active=false
-       #test $finish_count -gt $start_count && up=true
-
-       # Do we have enough devices for the mirror images?
-       if [ $start_count_p1 -gt ${#dev_array[@]} ]; then
-               echo "Action requires too many devices"
-               return 1
-       fi
-
-       # Do we have enough devices for the mirror images?
-       if [ $finish_count_p1 -gt ${#dev_array[@]} ]; then
-               echo "Action requires too many devices"
-               return 1
-       fi
-
-       start_log_count=`log_name_to_count $start_log_type`
-       finish_log_count=`log_name_to_count $finish_log_type`
-       if [ $finish_log_count -gt $start_log_count ]; then
-               max_log_count=$finish_log_count
-       else
-               max_log_count=$start_log_count
-       fi
-
-       prepare_vg 5
-
-       if [ $start_count -gt 0 ]; then
-               # Are there extra devices for the log or do we overlap
-               if [ $(($start_count_p1 + $start_log_count)) -gt ${#dev_array[@]} ]; then
-                       alloc="--alloc anywhere"
-               fi
-
-               lvcreate -l2 -m $start_count --mirrorlog $start_log_type \
-                       -n $lv1 $vg $alloc
-               check mirror_legs $vg $lv1 $start_count_p1
-               # FIXME: check mirror log
-       else
-               lvcreate -l2 -n $lv1 $vg
-       fi
-
-       lvs -a -o name,copy_percent,devices $vg
-       if ! $active; then
-               lvchange -an $vg/$lv1
-       fi
-
-       # Are there extra devices for the log or do we overlap
-       if [ $(($finish_count_p1 + $finish_log_count)) -gt ${#dev_array[@]} ]; then
-               alloc="--alloc anywhere"
-       fi
-
-       echo y | lvconvert -m $finish_count --mirrorlog $finish_log_type \
-               $vg/$lv1 $alloc
-
-       if ! $active; then
-               lvchange -ay $vg/$lv1
-       fi
-
-       check mirror_no_temporaries $vg $lv1
-       if [ "$finish_count_p1" -eq 1 ]; then
-               check linear $vg $lv1
-       else
-               if test -n "$alloc"; then
-                       check mirror_nonredundant $vg $lv1
-               else
-                       check mirror $vg $lv1
-               fi
-               check mirror_legs $vg $lv1 $finish_count_p1
-       fi
-}
-
-aux prepare_vg 5
-
-test_many() {
-       i=$1
-       for j in $(seq 0 3); do
-               for k in core disk mirrored; do
-                       for l in core disk mirrored; do
-                               if test "$i" -eq "$j" && test "$k" = "$l"; then continue; fi
-                               : ----------------------------------------------------
-                               : "Testing mirror conversion -m$i/$k -> -m$j/$l"
-                               : ----------------------------------------------------
-                               test_lvconvert $i $k $j $l 0
-                               test_lvconvert $i $k $j $l 1
-                       done
-               done
-       done
-}
diff --git a/test/t-lvconvert-mirror.sh b/test/t-lvconvert-mirror.sh
deleted file mode 100644 (file)
index c33196c..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-# convert from linear to 2-way mirror
-aux prepare_vg 5
-lvcreate -l2 -n $lv1 $vg $dev1
-lvconvert -i1 -m+1 $vg/$lv1 $dev2 $dev3:0-1
-check mirror $vg $lv1 $dev3
-
-# convert from 2-way mirror to linear
-aux prepare_vg 5
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev3:0-1
-lvconvert -m-1 $vg/$lv1
-check linear $vg $lv1
-lvremove -ff $vg
-# and now try removing a specific leg (bz453643)
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev3:0-1
-lvconvert -m0 $vg/$lv1 $dev2
-check lv_on $vg $lv1 $dev1
-lvremove -ff $vg
-
-# convert from disklog to corelog, active
-aux prepare_vg 5
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev3:0-1
-lvconvert -f --mirrorlog core $vg/$lv1
-check mirror $vg $lv1 core
-lvremove -ff $vg
-
-# convert from corelog to disklog, active
-aux prepare_vg 5
-lvcreate -l2 -m1 --mirrorlog core -n $lv1 $vg $dev1 $dev2
-lvconvert --mirrorlog disk $vg/$lv1 $dev3:0-1
-check mirror $vg $lv1 $dev3
-lvremove -ff $vg
-
-# bz192865: lvconvert log of an inactive mirror lv
-# convert from disklog to corelog, inactive
-aux prepare_vg 5
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev3:0-1
-lvchange -an $vg/$lv1
-echo y | lvconvert -f --mirrorlog core $vg/$lv1
-check mirror $vg $lv1 core
-lvremove -ff $vg
-
-# convert from corelog to disklog, inactive
-aux prepare_vg 5
-lvcreate -l2 -m1 --mirrorlog core -n $lv1 $vg $dev1 $dev2
-lvchange -an $vg/$lv1
-lvconvert --mirrorlog disk $vg/$lv1 $dev3:0-1
-check mirror $vg $lv1 $dev3
-lvremove -ff $vg
-
-# convert linear to 2-way mirror with 1 PV
-aux prepare_vg 5
-lvcreate -l2 -n $lv1 $vg $dev1
-not lvconvert -m+1 --mirrorlog core $vg/$lv1 $dev1
-lvremove -ff $vg
-
-# Start w/ 3-way mirror
-# Test pulling primary image before mirror in-sync (should fail)
-# Test pulling primary image after mirror in-sync (should work)
-# Test that the correct devices remain in the mirror
-lvcreate -l2 -m2 -n $lv1 $vg $dev1 $dev2 $dev4 $dev3:0
-# FIXME:
-#  This is somewhat timing dependent - sync /could/ finish before
-#  we get a chance to have this command fail
-should not lvconvert -m-1 $vg/$lv1 $dev1
-
-lvconvert $vg/$lv1 # wait
-lvconvert -m2 $vg/$lv1 $dev1 $dev2 $dev4 $dev3:0 # If the above "should" failed...
-
-lvconvert -m-1 $vg/$lv1 $dev1
-check mirror_images_on $lv1 $dev2 $dev4
-lvconvert -m-1 $vg/$lv1 $dev2
-check linear $vg $lv1
-check lv_on $vg $lv1 $dev4
-
-# No parallel lvconverts on a single LV please
-
-aux prepare_vg 5
-lvcreate -l5 -m1 -n $lv1 $vg $dev1 $dev2 $dev3:0
-check mirror $vg $lv1
-check mirror_legs $vg $lv1 2
-lvconvert -m+1 -b $vg/$lv1 $dev4
-
-# Next convert should fail b/c we can't have 2 at once
-should not lvconvert -m+1 $vg/$lv1 $dev5
-lvconvert $vg/$lv1 # wait
-lvconvert -m2 $vg/$lv1 # In case the above "should" actually failed
-
-check mirror $vg $lv1 $dev3
-check mirror_no_temporaries $vg $lv1
-check mirror_legs $vg $lv1 3
-
-# add 1 mirror to core log mirror, but
-#  implicitly keep log as 'core'
-aux prepare_vg 5
-lvcreate -l2 -m1 --mirrorlog core -n $lv1 $vg $dev1 $dev2
-lvconvert -m +1 -i1 $vg/$lv1
-
-check mirror $vg $lv1 core
-check mirror_no_temporaries $vg $lv1
-check mirror_legs $vg $lv1 3
-
-# remove 1 mirror from corelog'ed mirror; should retain 'core' log type
-aux prepare_vg 5
-lvcreate -l2 -m2 --corelog -n $lv1 $vg
-lvconvert -m -1 -i1 $vg/$lv1
-
-check mirror $vg $lv1 core
-check mirror_no_temporaries $vg $lv1
-check mirror_legs $vg $lv1 2
-
-# add 1 mirror then add 1 more mirror during conversion
-# FIXME this has been explicitly forbidden?
-#aux prepare_vg 5
-#lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev3:0
-#lvconvert -m+1 -b $vg/$lv1 $dev4
-#lvconvert -m+1 $vg/$lv1 $dev5
-#
-#check mirror $vg $lv1 $dev3
-#check mirror_no_temporaries $vg $lv1
-#check mirror_legs $vg $lv1 4
-
-# Linear to mirror with mirrored log using --alloc anywhere
-aux prepare_vg 5
-lvcreate -l2 -n $lv1 $vg $dev1
-lvconvert -m +1 --mirrorlog mirrored $vg/$lv1 $dev1 $dev2 --alloc anywhere
-should check mirror $vg $lv1
-
-# convert inactive mirror and start polling
-aux prepare_vg 5
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev3:0
-lvchange -an $vg/$lv1
-lvconvert -m+1 $vg/$lv1 $dev4
-lvchange -ay $vg/$lv1
-lvconvert $vg/$lv1 # wait
-check mirror $vg $lv1 $dev3
-check mirror_no_temporaries $vg $lv1
-
-# ---------------------------------------------------------------------
-# removal during conversion
-
-# "remove newly added mirror"
-aux prepare_vg 5
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev3:0
-lvconvert -m+1 -b $vg/$lv1 $dev4
-lvconvert -m-1 $vg/$lv1 $dev4
-lvconvert $vg/$lv1 # wait
-
-check mirror $vg $lv1 $dev3
-check mirror_no_temporaries $vg $lv1
-check mirror_legs $vg $lv1 2
-
-# "remove one of newly added mirrors"
-aux prepare_vg 5
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev3:0
-lvconvert -m+2 -b $vg/$lv1 $dev4 $dev5
-lvconvert -m-1 $vg/$lv1 $dev4
-lvconvert $vg/$lv1 # wait
-
-check mirror $vg $lv1 $dev3
-check mirror_no_temporaries $vg $lv1
-check mirror_legs $vg $lv1 3
-
-# "remove from original mirror (the original is still mirror)"
-aux prepare_vg 5
-lvcreate -l2 -m2 -n $lv1 $vg $dev1 $dev2 $dev5 $dev3:0
-lvconvert -m+1 -b $vg/$lv1 $dev4 
-lvconvert -m-1 $vg/$lv1 $dev2 
-lvconvert $vg/$lv1 
-
-check mirror $vg $lv1 $dev3
-check mirror_no_temporaries $vg $lv1
-check mirror_legs $vg $lv1 3
-
-# "remove from original mirror (the original becomes linear)"
-aux prepare_vg 5
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev3:0
-lvconvert -m+1 -b $vg/$lv1 $dev4 
-lvconvert -m-1 $vg/$lv1 $dev2 
-lvconvert $vg/$lv1 
-
-check mirror $vg $lv1 $dev3
-check mirror_no_temporaries $vg $lv1
-check mirror_legs $vg $lv1 2
-
-# ---------------------------------------------------------------------
-
-# "rhbz440405: lvconvert -m0 incorrectly fails if all PEs allocated"
-aux prepare_vg 5
-lvcreate -l`pvs --noheadings -ope_count $dev1` -m1 -n $lv1 $vg $dev1 $dev2 $dev3:0
-while [ `lvs --noheadings -o copy_percent $vg/$lv1` != "100.00" ]; do sleep 1; done
-lvconvert -m0 $vg/$lv1 $dev1
-check linear $vg $lv1
-
-# "rhbz264241: lvm mirror doesn't lose it's "M" --nosync attribute after being down and the up converted"
-aux prepare_vg 5
-lvcreate -l2 -m1 -n$lv1 --nosync $vg 
-lvconvert -m0 $vg/$lv1
-lvconvert -m1 $vg/$lv1
-lvs --noheadings -o attr $vg/$lv1 | grep '^ *m'
-
-# lvconvert from linear (on multiple PVs) to mirror
-aux prepare_vg 5
-lvcreate -l 8 -n $lv1 $vg $dev1:0-3 $dev2:0-3
-lvconvert -m1 $vg/$lv1
-
-should check mirror $vg $lv1
-check mirror_legs $vg $lv1 2
-
-# BZ 463272: disk log mirror convert option is lost if downconvert option is also given
-aux prepare_vg 5
-lvcreate -l1 -m2 --corelog -n $lv1 $vg $dev1 $dev2 $dev3
-while [ `lvs --noheadings -o copy_percent $vg/$lv1` != "100.00" ]; do sleep 1; done
-lvconvert -m1 --mirrorlog disk $vg/$lv1
-check mirror $vg $lv1
-not check mirror $vg $lv1 core
-
-# ---
-# add mirror and disk log
-
-# "add 1 mirror and disk log" 
-aux prepare_vg 5
-lvcreate -l2 -m1 --mirrorlog core -n $lv1 $vg $dev1 $dev2
-
-# FIXME on next line, specifying $dev3:0 $dev4 (i.e log device first) fails (!)
-lvconvert -m+1 --mirrorlog disk -i1 $vg/$lv1 $dev4 $dev3:0
-
-check mirror $vg $lv1 $dev3
-check mirror_no_temporaries $vg $lv1
-check mirror_legs $vg $lv1 3
diff --git a/test/t-lvconvert-repair-dmeventd.sh b/test/t-lvconvert-repair-dmeventd.sh
deleted file mode 100644 (file)
index f80a410..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-prepare_vg 5
-prepare_dmeventd
-
-which mkfs.ext2 || exit 200
-
-lvcreate -m 3 --ig -L 1 -n 4way $vg
-lvchange --monitor y $vg/4way
-disable_dev $dev2 $dev4
-mkfs.ext2 $DM_DEV_DIR/$vg/4way
-sleep 10 # FIXME: need a "poll" utility, akin to "check"
-enable_dev $dev2 $dev4
-check mirror $vg 4way
-check mirror_legs $vg 4way 2
diff --git a/test/t-lvconvert-repair-policy.sh b/test/t-lvconvert-repair-policy.sh
deleted file mode 100644 (file)
index 1f31215..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-prepare_vg 4
-
-# Clean-up and create a 2-way mirror, where the the
-# leg devices are always on $dev[12] and the log
-# is always on $dev3.  ($dev4 behaves as a spare)
-cleanup() {
-       vgreduce --removemissing $vg
-       for d in "$@"; do enable_dev $d; done
-       for d in "$@"; do vgextend $vg $d; done
-       lvremove -ff $vg/mirror
-       lvcreate -m 1 --ig -l 2 -n mirror $vg $dev1 $dev2 $dev3:0
-}
-
-repair() {
-       lvconvert --repair --use-policies --config "$1" $vg/mirror
-}
-
-lvcreate -m 1 -L 1 -n mirror $vg
-lvchange -a n $vg/mirror
-
-# Fail a leg of a mirror.
-aux disable_dev $dev1
-lvchange --partial -a y $vg/mirror
-repair 'activation { mirror_image_fault_policy = "remove" }'
-check linear $vg mirror
-aux cleanup $dev1
-
-# Fail a leg of a mirror.
-# Expected result: Mirror (leg replaced)
-aux disable_dev $dev1
-repair 'activation { mirror_image_fault_policy = "replace" }'
-check mirror $vg mirror
-lvs | grep mirror_mlog
-aux cleanup $dev1
-
-# Fail a leg of a mirror (use old name for policy specification)
-# Expected result: Mirror (leg replaced)
-aux disable_dev $dev1
-repair 'activation { mirror_device_fault_policy = "replace" }'
-check mirror $vg mirror
-lvs | grep mirror_mlog
-aux cleanup $dev1
-
-# Fail a leg of a mirror w/ no available spare
-# Expected result: 2-way with corelog
-aux disable_dev $dev2 $dev4
-repair 'activation { mirror_image_fault_policy = "replace" }'
-check mirror $vg mirror
-lvs | not grep mirror_mlog
-aux cleanup $dev2 $dev4
-
-# Fail the log device of a mirror w/ no available spare
-# Expected result: mirror w/ corelog
-aux disable_dev $dev3 $dev4
-repair 'activation { mirror_image_fault_policy = "replace" }' $vg/mirror
-check mirror $vg mirror
-lvs | not grep mirror_mlog
-aux cleanup $dev3 $dev4
-
-# Fail the log device with a remove policy
-# Expected result: mirror w/ corelog
-lvchange -a y $vg/mirror
-aux disable_dev $dev3 $dev4
-repair 'activation { mirror_log_fault_policy = "remove" }'
-check mirror $vg mirror core
-lvs | not grep mirror_mlog
-cleanup $dev3 $dev4
diff --git a/test/t-lvconvert-repair-replace.sh b/test/t-lvconvert-repair-replace.sh
deleted file mode 100644 (file)
index 7315a0e..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-prepare_vg 6
-
-# multiple failures, full replace
-lvcreate --mirrorlog disk -m 2 --ig -L 1 -n 3way $vg $dev1 $dev2 $dev3 $dev4:0-1
-disable_dev $dev1 $dev2
-echo y | lvconvert --repair $vg/3way 2>&1 | tee 3way.out
-lvs -a -o +devices | not grep unknown
-not grep "WARNING: Failed" 3way.out
-vgreduce --removemissing $vg
-check mirror $vg 3way
-enable_dev $dev1 $dev2
-
-vgremove -ff $vg; vgcreate -c n $vg $dev1 $dev2 $dev3 $dev4 $dev5
-
-# multiple failures, partial replace
-lvcreate --mirrorlog disk -m 2 --ig -L 1 -n 3way $vg $dev1 $dev2 $dev3 $dev4
-disable_dev $dev1 $dev2
-echo y | lvconvert --repair $vg/3way 2>&1 | tee 3way.out
-grep "WARNING: Failed" 3way.out
-lvs -a -o +devices | not grep unknown
-vgreduce --removemissing $vg
-check mirror $vg 3way
-enable_dev $dev1 $dev2
-lvchange -a n $vg/3way
-
-vgremove -ff $vg; vgcreate -c n $vg $dev1 $dev2 $dev3
-
-lvcreate --mirrorlog disk -m 1 --ig -L 1 -n 2way $vg $dev1 $dev2 $dev3
-disable_dev $dev1
-echo y | lvconvert --repair $vg/2way 2>&1 | tee 2way.out
-grep "WARNING: Failed" 2way.out
-lvs -a -o +devices | not grep unknown
-vgreduce --removemissing $vg
-check mirror $vg 2way
-enable_dev $dev1 $dev2
-lvchange -a n $vg/2way
-
-vgremove -ff $vg; vgcreate -c n $vg $dev1 $dev2 $dev3 $dev4
-
-# Test repair of inactive mirror with log failure
-#  Replacement should fail, but covert should succeed (switch to corelog)
-lvcreate -m 2 --ig -l 2 -n mirror2 $vg $dev1 $dev2 $dev3 $dev4:0
-vgchange -a n $vg
-pvremove -ff -y $dev4
-echo 'y' | lvconvert -y --repair $vg/mirror2
-check mirror $vg mirror2
-vgs
-
diff --git a/test/t-lvconvert-repair-transient.sh b/test/t-lvconvert-repair-transient.sh
deleted file mode 100644 (file)
index b4e1a06..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-prepare_vg 5
-
-exit 200 # this breaks upstream .33 and RHEL6 kernel :(
-
-# fail multiple devices
-
-lvcreate -m 3 --ig -L 1 -n 4way $vg
-disable_dev $dev2 $dev4
-mkfs.ext3 $DM_DEV_DIR/$vg/4way
-enable_dev $dev2 $dev4
-echo n | lvconvert --repair $vg/4way 2>&1 | tee 4way.out
-lvs -a -o +devices | not grep unknown
-vgreduce --removemissing $vg
-check mirror $vg 4way
-lvchange -a n $vg/4way
diff --git a/test/t-lvconvert-repair.sh b/test/t-lvconvert-repair.sh
deleted file mode 100644 (file)
index bce8b53..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-
-# fail multiple devices
-
-aux prepare_vg 5
-lvcreate -m 3 --ig -L 1 -n 4way $vg $dev1 $dev2 $dev3 $dev4 $dev5:0
-disable_dev $dev2 $dev4
-echo n | lvconvert --repair $vg/4way 2>&1 | tee 4way.out
-lvs -a -o +devices | not grep unknown
-vgreduce --removemissing $vg
-enable_dev $dev2 $dev4
-check mirror $vg 4way $dev5
-
-aux prepare_vg 5
-lvcreate -m 2 --ig -L 1 -n 3way $vg
-disable_dev $dev1 $dev2
-echo n | lvconvert --repair $vg/3way
-check linear $vg 3way
-lvs -a -o +devices | not grep unknown
-lvs -a -o +devices | not grep mlog
-dmsetup ls | grep $PREFIX | not grep mlog
-vgreduce --removemissing $vg
-enable_dev $dev1 $dev2
-check linear $vg 3way
-
-# fail just log and get it removed
-
-aux prepare_vg 5
-lvcreate -m 2 --ig -L 1 -n 3way $vg $dev1 $dev2 $dev3 $dev4:0
-disable_dev $dev4
-echo n | lvconvert --repair $vg/3way
-check mirror $vg 3way core
-lvs -a -o +devices | not grep unknown
-lvs -a -o +devices | not grep mlog
-dmsetup ls | grep $PREFIX | not grep mlog
-vgreduce --removemissing $vg
-enable_dev $dev4
-
-aux prepare_vg 5
-lvcreate -m 1 --ig -L 1 -n 2way $vg $dev1 $dev2 $dev3:0
-disable_dev $dev3
-echo n | lvconvert --repair $vg/2way
-check mirror $vg 2way core
-lvs -a -o +devices | not grep unknown
-lvs -a -o +devices | not grep mlog
-vgreduce --removemissing $vg
-enable_dev $dev3
-
-# fail single devices
-
-aux prepare_vg 5
-vgreduce $vg $dev4
-
-lvcreate -m 1 --ig -L 1 -n mirror $vg
-lvchange -a n $vg/mirror
-vgextend $vg $dev4
-disable_dev $dev1
-lvchange --partial -a y $vg/mirror
-
-not vgreduce -v --removemissing $vg
-lvconvert -y --repair $vg/mirror
-vgreduce --removemissing $vg
-
-enable_dev $dev1
-vgextend $vg $dev1
-disable_dev $dev2
-lvconvert -y --repair $vg/mirror
-vgreduce --removemissing $vg
-
-enable_dev $dev2
-vgextend $vg $dev2
-disable_dev $dev3
-lvconvert -y --repair $vg/mirror
-vgreduce --removemissing $vg
-enable_dev $dev3
-vgextend $vg $dev3
-lvremove -ff $vg
diff --git a/test/t-lvconvert-twostep.sh b/test/t-lvconvert-twostep.sh
deleted file mode 100644 (file)
index c499fdd..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-aux prepare_vg 4
-lvcreate -m 1 --mirrorlog disk --ig -L 1 -n mirror $vg
-not lvconvert -m 2 --mirrorlog core $vg/mirror $dev3 2>&1 | tee errs
-grep "two steps" errs
-lvconvert -m 2 $vg/mirror $dev3
-lvconvert --mirrorlog core $vg/mirror
-not lvconvert -m 1 --mirrorlog disk $vg/mirror $dev3 2>&1 | tee errs
-grep "two steps" errs
diff --git a/test/t-lvcreate-mirror.sh b/test/t-lvcreate-mirror.sh
deleted file mode 100644 (file)
index ae3fceb..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-aux prepare_vg 5 80
-
-# 2-way mirror with corelog, 2 PVs
-lvcreate -l2 -m1 --mirrorlog core -n $lv1 $vg $dev1 $dev2
-check mirror_images_redundant $vg $lv1
-lvremove -ff $vg
-
-# 2-way mirror with disklog, 3 PVs
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev3:0-1
-check mirror_images_redundant $vg $lv1
-check mirror_log_on $vg $lv1 $dev3
-lvremove -ff $vg
-
-# 3-way mirror with disklog, 4 PVs
-lvcreate -l2 -m2 --mirrorlog disk -n $lv1 $vg $dev1 $dev2 $dev4 $dev3:0-1
-check mirror_images_redundant $vg $lv1
-check mirror_log_on $vg $lv1 $dev3
-lvremove -ff $vg
-
-# lvcreate --nosync is in 100% sync after creation (bz429342)
-lvcreate -l2 -m1 --nosync -n $lv1 $vg $dev1 $dev2 $dev3:0-1 2>out
-grep "New mirror won't be synchronised." out
-lvs -o copy_percent --noheadings $vg/$lv1 | grep 100.00
-lvremove -ff $vg
-
-# creating 2-way mirror with disklog from 2 PVs fails
-not lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2
diff --git a/test/t-lvcreate-operation.sh b/test/t-lvcreate-operation.sh
deleted file mode 100644 (file)
index 8a31759..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-# 'Exercise some lvcreate diagnostics'
-
-. ./test-utils.sh
-
-cleanup_lvs() {
-       lvremove -ff $vg
-       if dmsetup table|grep $vg; then
-               echo "ERROR: lvremove did leave some some mappings in DM behind!"
-               return 1
-       fi
-}
-
-prepare_pvs 2
-aux pvcreate --metadatacopies 0 $dev1
-aux vgcreate -c n $vg $devs
-
-# ---
-# Create snapshots of LVs on --metadatacopies 0 PV (bz450651)
-lvcreate -n$lv1 -l4 $vg $dev1
-lvcreate -n$lv2 -l4 -s $vg/$lv1
-cleanup_lvs
-
-# ---
-# Create mirror on two devices with mirrored log using --alloc anywhere
-lvcreate -m 1 -l4 -n $lv1 --mirrorlog mirrored $vg --alloc anywhere $dev1 $dev2
-cleanup_lvs
-
-# --
-# Create mirror on one dev with mirrored log using --alloc anywhere, should fail
-not lvcreate -m 1 -l4 -n $lv1 --mirrorlog mirrored $vg --alloc anywhere $dev1
-cleanup_lvs
diff --git a/test/t-lvcreate-pvtags.sh b/test/t-lvcreate-pvtags.sh
deleted file mode 100755 (executable)
index b9a4380..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-aux prepare_pvs 3
-# not required, just testing
-aux pvcreate --metadatacopies 0 $dev1
-
-vgcreate -c n $vg $devs
-pvchange --addtag fast $devs
-
-# 3 stripes with 3 PVs (selected by tag, @fast) is fine
-lvcreate -l3 -i3 $vg @fast
-
-# too many stripes(4) for 3 PVs
-not lvcreate -l4 -i4 $vg @fast
-
-# 2 stripes is too many with just one PV
-not lvcreate -l2 -i2 $vg $DM_DEV_DIR/mapper/pv1
-
-# lvcreate mirror
-lvcreate -l1 -m1 $vg @fast
-
-# lvcreate mirror w/corelog
-lvcreate -l1 -m2 --corelog $vg @fast
-
-# lvcreate mirror w/no free PVs
-not lvcreate -l1 -m2 $vg @fast
-
-# lvcreate mirror (corelog, w/no free PVs)
-not lvcreate -l1 -m3 --corelog $vg @fast
-
-# lvcreate mirror with a single PV arg
-not lvcreate -l1 -m1 --corelog $vg $dev1
diff --git a/test/t-lvcreate-small-snap.sh b/test/t-lvcreate-small-snap.sh
deleted file mode 100644 (file)
index 789c099..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-aux prepare_pvs 3
-
-vgcreate -c n -s 1k $vg $devs
-
-lvcreate -n one -l 10 $vg
-lvcreate -s -l 8 -n snapA $vg/one
-lvcreate -s -c 4k -l 8 -n snapX1 $vg/one
-lvcreate -s -c 8k -l 16 -n snapX2 $vg/one
-
-# Check that snapshots that are too small are caught with correct error.
-not lvcreate -s -c 8k -l 8 -n snapX3 $vg/one 2>&1 | tee lvcreate.out
-not grep "suspend origin one" lvcreate.out
-grep "Unable to create a snapshot" lvcreate.out
-
-not lvcreate -s -l 4 -n snapB $vg/one 2>&1 | tee lvcreate.out
-not grep "suspend origin one" lvcreate.out
-grep "Unable to create a snapshot" lvcreate.out
diff --git a/test/t-lvcreate-usage.sh b/test/t-lvcreate-usage.sh
deleted file mode 100755 (executable)
index 0bb06ab..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-# 'Exercise some lvcreate diagnostics'
-
-. ./test-utils.sh
-
-aux prepare_pvs 4
-aux pvcreate --metadatacopies 0 $dev1
-vgcreate -cn $vg $devs
-
-# "lvcreate rejects repeated invocation (run 2 times) (bz178216)" 
-lvcreate -n $lv -l 4 $vg 
-not lvcreate -n $lv -l 4 $vg
-lvremove -ff $vg/$lv
-# try to remove it again - should fail (but not segfault)
-not lvremove -ff $vg/$lv
-
-# "lvcreate rejects a negative stripe_size"
-not lvcreate -L 64m -n $lv -i2 --stripesize -4 $vg 2>err;
-grep "^  Negative stripesize is invalid\$" err
-
-# 'lvcreate rejects a too-large stripesize'
-not lvcreate -L 64m -n $lv -i2 --stripesize 4294967291 $vg 2>err
-grep "^  Stripe size cannot be larger than" err
-
-# 'lvcreate w/single stripe succeeds with diagnostics to stdout' 
-lvcreate -L 64m -n $lv -i1 --stripesize 4 $vg 2> err | tee out
-grep "^  Ignoring stripesize argument with single stripe\$" out 
-lvdisplay $vg 
-lvremove -ff $vg
-
-# 'lvcreate w/default (64KB) stripe size succeeds with diagnostics to stdout'
-lvcreate -L 64m -n $lv -i2 $vg > out
-grep "^  Using default stripesize" out 
-lvdisplay $vg 
-check_lv_field_ $vg/$lv stripesize "64.00k"
-lvremove -ff $vg
-
-# 'lvcreate rejects an invalid number of stripes' 
-not lvcreate -L 64m -n $lv -i129 $vg 2>err
-grep "^  Number of stripes (129) must be between 1 and 128\$" err
-
-# The case on lvdisplay output is to verify that the LV was not created.
-# 'lvcreate rejects an invalid stripe size'
-not lvcreate -L 64m -n $lv -i2 --stripesize 3 $vg 2>err
-grep "^  Invalid stripe size" err
-case $(lvdisplay $vg) in "") true ;; *) false ;; esac
-
-# Setting max_lv works. (bz490298)
-lvremove -ff $vg
-vgchange -l 3 $vg
-lvcreate -l1 -n $lv1 $vg
-lvcreate -l1 -s -n $lv2 $vg/$lv1
-lvcreate -l1 -n $lv3 $vg
-not lvcreate -l1 -n $lv4 $vg
-
-lvremove -ff $vg/$lv3
-lvcreate -l1 -s -n $lv3 $vg/$lv1
-not lvcreate -l1 -n $lv4 $vg
-not lvcreate -l1 -m1 -n $lv4 $vg
-
-lvremove -ff $vg/$lv3
-lvcreate -l1 -m1 -n $lv3 $vg
-lvs
-vgs -o +max_lv
-not lvcreate -l1 -n $lv4 $vg
-not lvcreate -l1 -m1 -n $lv4 $vg
-
-lvconvert -m0 $vg/$lv3
-lvconvert -m2 -i 1 $vg/$lv3
-lvconvert -m1 $vg/$lv3
-
-not vgchange -l 2
-vgchange -l 4
-vgs $vg
-
-lvremove -ff $vg
-vgchange -l 0 $vg
-
-# lvcreate rejects invalid chunksize, accepts between 4K and 512K
-# validate origin_size
-vgremove -ff $vg
-vgcreate -cn $vg $devs
-lvcreate -L 32m -n $lv1 $vg
-not lvcreate -L 8m -n $lv2 -s --chunksize 3k $vg/$lv1
-not lvcreate -L 8m -n $lv2 -s --chunksize 1024k $vg/$lv1
-lvcreate -L 8m -n $lv2 -s --chunksize 4k $vg/$lv1
-check_lv_field_ $vg/$lv2 chunk_size 4.00k
-check_lv_field_ $vg/$lv2 origin_size 32.00m
-lvcreate -L 8m -n $lv3 -s --chunksize 512k $vg/$lv1
-check_lv_field_ $vg/$lv3 chunk_size 512.00k
-check_lv_field_ $vg/$lv3 origin_size 32.00m
-lvremove -ff $vg
-vgchange -l 0 $vg
-
-# regionsize must be
-# - nonzero (bz186013)
-# - a power of 2 and a multiple of page size
-# - <= size of LV
-not lvcreate -L 32m -n $lv -R0 $vg 2>err
-grep "Non-zero region size must be supplied." err
-not lvcreate -L 32m -n $lv -R 11k $vg
-not lvcreate -L 32m -n $lv -R 1k $vg
-lvcreate -L 32m -n $lv --regionsize 128m  -m 1 $vg
-check_lv_field_ $vg/$lv regionsize "32.00m"
-lvremove -ff $vg
-lvcreate -L 32m -n $lv --regionsize 4m -m 1 $vg
-check_lv_field_ $vg/$lv regionsize "4.00m"
-lvremove -ff $vg
-
-# snapshot with virtual origin works
-lvcreate -s --virtualoriginsize 64m -L 32m -n $lv1 $vg
-lvrename $vg/$lv1 $vg/$lv2
-lvcreate -s --virtualoriginsize 64m -L 32m -n $lv1 $vg
-lvchange -a n $vg/$lv1
-lvremove $vg/$lv1
-lvremove -ff $vg
-
-# readahead default (auto), none, #, auto
-lvcreate -L 32m -n $lv $vg
-check_lv_field_ $vg/$lv lv_read_ahead "auto"
-lvremove -ff $vg
-lvcreate -L 32m -n $lv --readahead none $vg
-check_lv_field_ $vg/$lv lv_read_ahead "0"
-lvremove -ff $vg
-lvcreate -L 32m -n $lv --readahead 8k $vg
-check_lv_field_ $vg/$lv lv_read_ahead "8.00k"
-lvremove -ff $vg
-lvcreate -L 32m -n $lv --readahead auto $vg
-check_lv_field_ $vg/$lv lv_read_ahead "auto"
-lvremove -ff $vg
-
diff --git a/test/t-lvextend-percent-extents.sh b/test/t-lvextend-percent-extents.sh
deleted file mode 100755 (executable)
index d020dec..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-# 'Check extents percentage arguments'
-
-. ./test-utils.sh
-
-aux prepare_vg 2 128
-
-lvcreate -L 64m -n $lv $vg
-
-# 'lvextend rejects both size and extents without PVs'
-not lvextend -l 10 -L 64m $vg/$lv 2>err
-grep "^  Please specify either size or extents but not both.\$" err
-
-# 'lvextend rejects both size and extents with PVs'
-not lvextend -l 10 -L 64m $vg/$lv $dev1 2>err
-grep "^  Please specify either size or extents but not both.\$" err
-
-# 'lvextend accepts no size or extents but one PV - bz154691'
-lvextend $vg/$lv $dev1 >out
-grep "^  Logical volume $lv successfully resized\$" out
-check_pv_field_ $dev1 pv_free "0"
-
-lvremove -f $vg/$lv 
-
-# 'lvextend computes necessary free space correctly - bz213552'
-vgsize=$(vgs -o vg_extent_count --noheadings)
-lvcreate -l $vgsize  -n $lv $vg
-lvreduce -f -l $(( $vgsize / 2 )) $vg/$lv
-lvextend -l $vgsize $vg/$lv
-
-# 'Reset LV to original size' 
-lvremove -f $vg/$lv 
-lvcreate -L 64m -n $lv $vg
-
-# 'lvextend accepts no size but extents 100%PVS and two PVs - bz154691'
-lvextend -l +100%PVS $vg/$lv $dev1 $dev2 >out
-grep "^  Logical volume $lv successfully resized\$" out 
-check_pv_field_ $dev1 pv_free "0" 
-check_pv_field_ $dev2 pv_free "0"
-
-# Exercise the range overlap code.  Allocate every 2 extents.
-#
-#      Physical Extents
-#          1         2
-#012345678901234567890123
-#
-#aaXXaaXXaaXXaaXXaaXXaaXX - (a)llocated
-#rrrXXXrrrXXXrrrXXXrrrXXX - (r)ange on cmdline
-#ooXXXXXXoXXXooXXXXXXoXXX - (o)verlap of range and allocated
-#
-# Key: a - allocated
-#      F - free
-#      r - part of a range on the cmdline
-#      N - not on cmdline
-#
-# Create the LV with 12 extents, allocated every other 2 extents.
-# Then extend it, with a range of PVs on the cmdline of every other 3 extents.
-# Total number of extents should be 12 + overlap = 12 + 6 = 18.
-# Thus, total size for the LV should be 18 * 4M = 72M
-#
-# 'Reset LV to 12 extents, allocate every other 2 extents' 
-create_pvs=`for i in $(seq 0 4 20); do echo -n "\$dev1:$i-$(($i + 1)) "; done` 
-lvremove -f $vg/$lv
-lvcreate -l 12 -n $lv $vg $create_pvs
-check_lv_field_ $vg/$lv lv_size "48.00m"
-
-# 'lvextend with partially allocated PVs and extents 100%PVS with PE ranges' 
-extend_pvs=`for i in $(seq 0 6 18); do echo -n "\$dev1:$i-$(($i + 2)) "; done` 
-lvextend -l +100%PVS $vg/$lv $extend_pvs >out
-grep "^  Logical volume $lv successfully resized\$" out 
-check_lv_field_ $vg/$lv lv_size "72.00m"
-
-# Simple seg_count validation; initially create the LV with half the # of
-# extents (should be 1 lv segment), extend it (should go to 2 segments),
-# then reduce (should be back to 1)
-# FIXME: test other segment fields such as seg_size, pvseg_start, pvseg_size
-lvremove -f $vg/$lv
-pe_count=$(pvs -o pv_pe_count --noheadings $dev1)
-pe1=$(( $pe_count / 2 ))
-lvcreate -l $pe1 -n $lv $vg
-pesize=$(lvs -ovg_extent_size --units b --nosuffix --noheadings $vg/$lv)
-segsize=$(( $pe1 * $pesize / 1024 / 1024 ))m
-check_lv_field_ $vg/$lv seg_count 1
-check_lv_field_ $vg/$lv seg_start 0
-check_lv_field_ $vg/$lv seg_start_pe 0
-#check_lv_field_ $vg/$lv seg_size $segsize
-lvextend -l +$(( $pe_count * 1 )) $vg/$lv
-check_lv_field_ $vg/$lv seg_count 2
-lvreduce -f -l -$(( $pe_count * 1 )) $vg/$lv
-check_lv_field_ $vg/$lv seg_count 1
-
diff --git a/test/t-lvextend-snapshot-dmeventd.sh b/test/t-lvextend-snapshot-dmeventd.sh
deleted file mode 100644 (file)
index f1ed72f..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-extend() {
-       lvextend --use-policies --config "activation { snapshot_extend_threshold = $1 }" $vg/snap
-}
-
-write() {
-       mount $DM_DEV_DIR/$vg/snap mnt
-       dd if=/dev/zero of=mnt/file$1 bs=1k count=$2
-       umount mnt
-}
-
-percent() {
-       lvs $vg/snap -o snap_percent --noheadings | cut -c4- | cut -d. -f1
-}
-
-which mkfs.ext2 || exit 200
-
-aux prepare_vg 2
-aux prepare_dmeventd
-
-lvcreate -l 8 -n base $vg
-mkfs.ext2 $DM_DEV_DIR/$vg/base
-
-lvcreate -s -l 4 -n snap $vg/base
-lvchange --monitor y $vg/snap
-
-mkdir mnt
-
-write 1 4096
-pre=`percent`
-sleep 10 # dmeventd only checks every 10 seconds :(
-post=`percent`
-
-test $pre = $post
-write 2 5000
-pre=`percent`
-sleep 10 # dmeventd only checks every 10 seconds :(
-post=`percent`
-test $pre -gt $post
diff --git a/test/t-lvextend-snapshot-policy.sh b/test/t-lvextend-snapshot-policy.sh
deleted file mode 100644 (file)
index 76ea980..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-extend() {
-       lvextend --use-policies --config "activation { snapshot_extend_threshold = $1 }" $vg/snap
-}
-
-write() {
-       mount $DM_DEV_DIR/$vg/snap mnt
-       dd if=/dev/zero of=mnt/file$1 bs=1k count=$2
-       umount mnt
-}
-
-percent() {
-       lvs $vg/snap -o snap_percent --noheadings | cut -c4- | cut -d. -f1
-}
-
-which mkfs.ext2 || exit 200
-
-aux prepare_vg 2
-lvcreate -l 8 -n base $vg
-mkfs.ext2 $DM_DEV_DIR/$vg/base
-
-lvcreate -s -l 4 -n snap $vg/base
-mkdir mnt
-
-write 1 4096
-pre=`percent`
-extend 50
-post=`percent`
-
-test $pre = $post
-write 2 4096
-pre=`percent`
-extend 50
-post=`percent`
-test $pre -gt $post
diff --git a/test/t-lvm-init.sh b/test/t-lvm-init.sh
deleted file mode 100644 (file)
index cf324e4..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-#
-# tests lvm initialization, and especially negative tests of error paths
-#
-
-. ./test-utils.sh
-
-aux prepare_devs 5
-
-# invalid units
-not pvs --config 'global { units = "<" }'
-
diff --git a/test/t-lvmcache-exercise.sh b/test/t-lvmcache-exercise.sh
deleted file mode 100755 (executable)
index aecb4a9..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-aux prepare_pvs 5
-
-vgcreate $vg1 $dev1
-vgcreate $vg2 $dev3
-
-disable_dev $dev1
-pvscan
-vgcreate $vg1 $dev2
-enable_dev $dev1
-pvs
-pvs
diff --git a/test/t-lvresize-mirror.sh b/test/t-lvresize-mirror.sh
deleted file mode 100644 (file)
index 0d63102..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-aux prepare_vg 5 80
-
-# extend 2-way mirror
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev3:0-1
-lvchange -an $vg/$lv1
-lvextend -l+2 $vg/$lv1
-check mirror $vg $lv1 $dev3
-check mirror_images_contiguous $vg $lv1
-lvremove -ff $vg
-
-# reduce 2-way mirror
-lvcreate -l4 -m1 -n $lv1 $vg $dev1 $dev2 $dev3:0-1
-lvchange -an $vg/$lv1
-lvreduce -l-2 $vg/$lv1
-check mirror $vg $lv1 $dev3
-lvremove -ff $vg
-
-# extend 2-way mirror (cling if not contiguous)
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev3:0-1
-lvcreate -l1 -n $lv2 $vg $dev1
-lvcreate -l1 -n $lv3 $vg $dev2
-lvchange -an $vg/$lv1
-lvextend -l+2 $vg/$lv1
-check mirror $vg $lv1 $dev3
-check mirror_images_clung $vg $lv1
-lvremove -ff $vg
diff --git a/test/t-lvresize-usage.sh b/test/t-lvresize-usage.sh
deleted file mode 100755 (executable)
index d9860e9..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright (C) 2007-2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-aux prepare_vg 2
-
-lvcreate -L 10M -n lv -i2 $vg
-lvresize -l +4 $vg/lv
-lvremove -ff $vg
-
-lvcreate -L 64M -n $lv -i2 $vg
-not lvresize -v -l +4 xxx/$lv
diff --git a/test/t-mdata-strings.sh b/test/t-mdata-strings.sh
deleted file mode 100755 (executable)
index 66d472a..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-# 'Test for proper escaping of strings in metadata (bz431474)'
-
-. ./test-utils.sh
-
-aux prepare_devs 1
-
-pv_ugly="__\"!@#\$%^&*,()|@||'\\\"__pv1"
-
-# 'set up temp files, loopback devices' 
-name=$(basename "$dev1")
-dmsetup rename "$name" "$PREFIX$pv_ugly"
-dev1=$(dirname "$dev1")/$PREFIX$pv_ugly
-
-# 'pvcreate, vgcreate on filename with backslashed chars' 
-pvcreate "$dev1" 
-vgcreate $vg "$dev1"
-
-# 'no parse errors and VG really exists' 
-vgs 2>err
-not grep "Parse error" err;
-vgs $vg
-
diff --git a/test/t-metadata-balance.sh b/test/t-metadata-balance.sh
deleted file mode 100755 (executable)
index 79570d9..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-aux prepare_devs 6
-
-echo Make sure we can ignore / un-ignore mdas on a per-PV basis
-for pv_in_vg in 1 0; do
-for mdacp in 1 2; do
-       pvcreate --metadatacopies $mdacp $dev1 $dev2
-        pvcreate --metadatacopies 0 $dev3
-       if [ $pv_in_vg = 1 ]; then
-               vgcreate -c n "$vg" $dev1 $dev2 $dev3
-       fi
-       pvchange --metadataignore y $dev1
-       check_pv_field_ $dev1 pv_mda_count $mdacp
-       check_pv_field_ $dev1 pv_mda_used_count 0
-       check_pv_field_ $dev2 pv_mda_count $mdacp
-       check_pv_field_ $dev2 pv_mda_used_count $mdacp
-       if [ $pv_in_vg = 1 ]; then
-               check_vg_field_ $vg vg_mda_count $(($mdacp * 2))
-               check_vg_field_ $vg vg_mda_used_count $mdacp
-               check_vg_field_ $vg vg_mda_copies unmanaged
-       fi
-       pvchange --metadataignore n $dev1
-       check_pv_field_ $dev1 pv_mda_count $mdacp
-       check_pv_field_ $dev1 pv_mda_used_count $mdacp
-       if [ $pv_in_vg = 1 ]; then
-               check_vg_field_ $vg vg_mda_count $(($mdacp * 2))
-               check_vg_field_ $vg vg_mda_used_count $(($mdacp * 2))
-               check_vg_field_ $vg vg_mda_copies unmanaged
-               vgremove -f $vg
-       fi
-done
-done
-
-# Check if a PV has unignored (used) mdas, and if so, ignore
-pvignore_ () {
-       pv_mda_used_count=$(get_pv_field "$1" pv_mda_used_count)
-       if [ $pv_mda_used_count -ne 0 ]; then
-           pvchange --metadataignore y $1
-       fi
-}
-
-# Check if a PV has ignored mdas, and if so, unignore (make used)
-pvunignore_ () {
-       pv_mda_count=$(get_pv_field "$1" pv_mda_count)
-       pv_mda_used_count=$(get_pv_field "$1" pv_mda_used_count)
-       if [ $pv_mda_count -gt $pv_mda_used_count ]; then
-           pvchange --metadataignore n $1
-       fi
-}
-
-echo Test of vgmetadatacopies with vgcreate and vgchange
-for mdacp in 1 2; do
-       pvcreate --metadatacopies $mdacp $dev1 $dev2 $dev4 $dev5
-       check_pv_field_ $dev1 pv_mda_used_count $mdacp
-       check_pv_field_ $dev2 pv_mda_used_count $mdacp
-       check_pv_field_ $dev4 pv_mda_used_count $mdacp
-       check_pv_field_ $dev5 pv_mda_used_count $mdacp
-       pvcreate --metadatacopies 0 $dev3
-       vgcreate -c n "$vg" $dev1 $dev2 $dev3
-       check_vg_field_ $vg vg_mda_copies unmanaged
-       echo ensure both --vgmetadatacopies and --metadatacopies accepted
-       vgchange --metadatacopies $(($mdacp * 1)) $vg
-       echo --vgmetadatacopies is persistent on disk
-       echo --vgmetadatacopies affects underlying pv mda ignore
-       check_vg_field_ $vg vg_mda_copies $(($mdacp * 1))
-       check_vg_field_ $vg vg_mda_used_count $(($mdacp * 1))
-       vgchange --vgmetadatacopies $(($mdacp * 2)) $vg
-       check_vg_field_ $vg vg_mda_copies $(($mdacp * 2))
-       check_vg_field_ $vg vg_mda_used_count $(($mdacp * 2))
-       echo allow setting metadatacopies larger than number of PVs
-       vgchange --vgmetadatacopies $(($mdacp * 5)) $vg
-       check_vg_field_ $vg vg_mda_copies $(($mdacp * 5))
-       check_vg_field_ $vg vg_mda_used_count $(($mdacp * 2))
-       echo setting to 0 disables automatic balancing
-       vgchange --vgmetadatacopies unmanaged $vg
-       check_vg_field_ $vg vg_mda_copies unmanaged
-       vgremove -f $vg
-       echo vgcreate succeeds even when creating a VG w/all ignored mdas
-       pvchange --metadataignore y $dev1 $dev2
-       check_pv_field_ $dev1 pv_mda_count $mdacp
-       check_pv_field_ $dev2 pv_mda_used_count 0
-       vgcreate -c n "$vg" $dev1 $dev2
-       check_vg_field_ $vg vg_mda_copies unmanaged
-       vgremove -f $vg
-       echo vgcreate succeeds with a specific number of metadata copies
-       vgcreate -c n --vgmetadatacopies $(($mdacp * 2)) "$vg" $dev1 $dev2
-       check_vg_field_ $vg vg_mda_copies $(($mdacp * 2))
-       vgremove -f $vg
-       vgcreate -c n --vgmetadatacopies $(($mdacp * 1)) "$vg" $dev1 $dev2
-       check_vg_field_ $vg vg_mda_copies $(($mdacp * 1))
-       vgremove -f $vg
-       echo vgcreate succeeds with a larger value than total metadatacopies
-       vgcreate -c n --vgmetadatacopies $(($mdacp * 5)) "$vg" $dev1 $dev2
-       check_vg_field_ $vg vg_mda_copies $(($mdacp * 5))
-       vgremove -f $vg
-       echo vgcreate succeeds with --vgmetadatacopies unmanaged
-       vgcreate -c n --vgmetadatacopies unmanaged "$vg" $dev1 $dev2
-       check_vg_field_ $vg vg_mda_copies unmanaged
-       vgremove -f $vg
-       pvunignore_ $dev1
-       pvunignore_ $dev2
-       pvunignore_ $dev4
-       pvunignore_ $dev5
-       echo vgcreate succeds with small value of --metadatacopies, ignores mdas
-       vgcreate -c n --vgmetadatacopies 1 "$vg" $dev1 $dev2 $dev4 $dev5
-       check_vg_field_ $vg vg_mda_copies 1
-       check_vg_field_ $vg vg_mda_count $(($mdacp * 4))
-       check_vg_field_ $vg vg_mda_used_count 1
-       echo Setting a larger value should trigger non-ignore of mdas
-       vgchange --metadatacopies 3 $vg
-       check_vg_field_ $vg vg_mda_copies 3
-       check_vg_field_ $vg vg_mda_used_count 3
-       echo Setting all should trigger unignore of all mdas
-       vgchange --vgmetadatacopies all $vg
-       check_vg_field_ $vg vg_mda_count $(($mdacp * 4))
-       check_vg_field_ $vg vg_mda_copies unmanaged
-       check_vg_field_ $vg vg_mda_used_count $(($mdacp * 4))
-       echo --vgmetadatacopies 0 should be unmanaged for vgchange and vgcreate
-       vgchange --vgmetadatacopies 0 $vg
-       check_vg_field_ $vg vg_mda_copies unmanaged
-       vgremove -f $vg
-       vgcreate -c n --vgmetadatacopies 0 "$vg" $dev1 $dev2 $dev4 $dev5
-       check_vg_field_ $vg vg_mda_copies unmanaged
-       vgremove -f $vg
-done
-
-echo Test vgextend / vgreduce with vgmetadatacopies
-for mdacp in 1 2; do
-       pvcreate --metadatacopies $mdacp $dev1 $dev2 $dev4 $dev5
-       pvcreate --metadatacopies 0 $dev3
-       echo Set a large value of vgmetadatacopies
-       vgcreate -c n --vgmetadatacopies $(($mdacp * 5)) "$vg" $dev1 $dev2 $dev3
-       check_vg_field_ $vg vg_mda_copies $(($mdacp * 5))
-       echo Ignore mdas on devices to be used for vgextend
-       echo Large value of vgetadatacopies should automatically un-ignore mdas
-       pvchange --metadataignore y $dev4 $dev5
-       check_pv_field_ $dev4 pv_mda_used_count 0
-       vgextend $vg $dev4 $dev5
-       check_pv_field_ $dev4 pv_mda_used_count $mdacp
-       check_pv_field_ $dev5 pv_mda_used_count $mdacp
-       vgremove -f $vg
-       echo Set a small value of vgmetadatacopies
-       vgcreate -c n --vgmetadatacopies $(($mdacp * 1)) "$vg" $dev1 $dev2 $dev3
-       check_vg_field_ $vg vg_mda_copies $(($mdacp * 1))
-       echo Ignore mdas on devices to be used for vgextend
-       echo Small value of vgetadatacopies should leave mdas as ignored
-       pvchange --metadataignore y $dev4 $dev5
-       check_pv_field_ $dev4 pv_mda_used_count 0
-       vgextend $vg $dev4 $dev5
-       check_pv_field_ $dev4 pv_mda_used_count 0
-       check_pv_field_ $dev5 pv_mda_used_count 0
-       echo vgreduce of ignored pv w/mda should not trigger any change to ignore bits
-       vgreduce $vg $dev4
-       check_pv_field_ $dev4 pv_mda_used_count 0
-       check_pv_field_ $dev5 pv_mda_used_count 0
-       echo vgreduce of un-ignored pv w/mda should trigger un-ignore on an mda
-       vgreduce $vg $dev1 $dev2 $dev3
-       check_pv_field_ $dev5 pv_mda_used_count $mdacp
-       check_vg_field_ $vg vg_mda_copies $(($mdacp * 1))
-       pvunignore_ $dev1
-       pvunignore_ $dev2
-       echo setting vgmetadatacopies to unmanaged should allow vgextend to add w/out balancing
-       vgchange --vgmetadatacopies unmanaged $vg
-       vgextend $vg $dev1 $dev2
-       check_vg_field_ $vg vg_mda_copies unmanaged
-       check_vg_field_ $vg vg_mda_count $(($mdacp * 3))
-       check_vg_field_ $vg vg_mda_used_count $((mdacp * 3))
-       check_pv_field_ $dev1 pv_mda_used_count $mdacp
-       check_pv_field_ $dev2 pv_mda_used_count $mdacp
-       vgremove -f $vg
-done
-
-echo Test special situations, vgsplit, vgmerge, etc
-for mdacp in 1 2; do
-       pvcreate --metadatacopies $mdacp $dev1 $dev2 $dev3 $dev4 $dev5
-       vgcreate -c n --vgmetadatacopies 2 $vg1 $dev1 $dev2 $dev3
-       vgcreate -c n --vgmetadatacopies $(($mdacp * 1)) $vg2 $dev4 $dev5
-       echo vgsplit/vgmerge preserves value of metadata copies
-       check_vg_field_ $vg1 vg_mda_copies 2
-       check_vg_field_ $vg2 vg_mda_copies $(($mdacp * 1))
-       vgsplit $vg1 $vg2 $dev1
-       check_vg_field_ $vg2 vg_mda_copies $(($mdacp * 1))
-       vgmerge $vg1 $vg2
-       check_vg_field_ $vg1 vg_mda_copies 2
-       check_vg_field_ $vg1 vg_mda_count $(($mdacp * 5))
-       echo vgsplit into new vg sets proper value of vgmetadatacopies
-       vgsplit --vgmetadatacopies $(($mdacp * 2)) $vg1 $vg2 $dev1 $dev2
-       check_vg_field_ $vg2 vg_mda_copies $(($mdacp * 2))
-       echo vgchange fails if given both vgmetadatacopies and metadatacopies
-       not vgchange --vgmetadatacopies 5 --metadatacopies 7 $vg2
-       vgremove -f $vg1
-       vgremove -f $vg2
-done
-
-echo Test combination of --vgmetadatacopies and pvchange --metadataignore
-for mdacp in 1 2; do
-       pvcreate --metadatacopies $mdacp $dev1 $dev2 $dev3 $dev4 $dev5
-       vgcreate -c n --vgmetadatacopies $(($mdacp * 1)) $vg1 $dev1 $dev2
-       check_vg_field_ $vg1 vg_mda_copies $(($mdacp * 1))
-       check_vg_field_ $vg1 vg_mda_used_count $(($mdacp * 1))
-       pvignore_ $dev3
-       echo Ensure vgextend of PVs with ignored MDAs does not add to vg_mda_used_count
-       vgextend $vg1 $dev3
-       check_vg_field_ $vg1 vg_mda_used_count $(($mdacp * 1))
-       echo Using pvchange to unignore should update vg_mda_used_count
-       pvchange -f --metadataignore n $dev3
-       check_pv_field_ $dev3 pv_mda_used_count $mdacp
-       check_vg_field_ $vg1 vg_mda_used_count $(($mdacp * 2))
-       echo Set unmanaged on the vg should keep ignore bits the same during vgextend
-       vgchange --vgmetadatacopies unmanaged $vg1
-       check_vg_field_ $vg1 vg_mda_used_count $(($mdacp * 2))
-       pvunignore_ $dev4
-       vgextend $vg1 $dev4
-       check_pv_field_ $dev4 pv_mda_used_count $mdacp
-       check_vg_field_ $vg1 vg_mda_used_count $(($mdacp * 3))
-       echo Using pvchange to ignore should update vg_mda_used_count
-       pvchange -f --metadataignore y $dev4
-       check_pv_field_ $dev4 pv_mda_used_count 0
-       check_vg_field_ $vg1 vg_mda_used_count $(($mdacp * 2))
-       vgremove -f $vg1
-done
diff --git a/test/t-metadata.sh b/test/t-metadata.sh
deleted file mode 100755 (executable)
index 49066c7..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-aux prepare_devs 5
-
-pvcreate $dev1
-pvcreate --metadatacopies 0 $dev2
-pvcreate --metadatacopies 0 $dev3
-pvcreate $dev4
-pvcreate --metadatacopies 0 $dev5
-
-vgcreate -c n "$vg" $devs
-lvcreate -n $lv -l 1 -i5 -I256 $vg
-
-pvchange -x n $dev1
-pvchange -x y $dev1
-vgchange -a n $vg
-pvchange --uuid $dev1
-pvchange --uuid $dev2
-vgremove -f $vg
-
-# check that PVs without metadata don't cause too many full device rescans (bz452606)
-for mdacp in 1 0; do
-       pvcreate --metadatacopies $mdacp $devs
-       pvcreate $dev1
-       vgcreate -c n $vg $devs
-       lvcreate -n $lv1 -l 2 -i5 -I256 $vg
-       lvcreate -n $lv2 -m2 -l 2  $vg
-       #lvchange -an $vg
-       lvchange -an $vg/$lv1
-       lvchange -an $vg/$lv2
-       vgchange -ay $vg
-       lvchange -vvvv -an $vg/$lv1 >out$mdacp 2>&1 
-       lvchange -vvvv -an $vg/$lv2 >>out$mdacp 2>&1 
-       vgremove -f $vg
-done
-not grep "Cached VG .* incorrect PV list" out0
-
-# some M1 metadata tests
-pvcreate -M1 $dev1
-pvcreate -M1 $dev2
-pvcreate -M1 $dev3
-pv3_uuid=$(pvs --noheadings -o pv_uuid $dev3)
-vgcreate -M1 -c n $vg $dev1 $dev2 $dev3
-pvchange --uuid $dev1
-
-# verify pe_start of all M1 PVs
-pv_align="128.00k"
-check_pv_field_ $dev1 pe_start $pv_align
-check_pv_field_ $dev2 pe_start $pv_align
-check_pv_field_ $dev3 pe_start $pv_align
-
-pvs --units k -o name,pe_start,vg_mda_size,vg_name
-
-# upgrade from v1 to v2 metadata
-vgconvert -M2 $vg
-
-# verify pe_start of all M2 PVs
-check_pv_field_ $dev1 pe_start $pv_align
-check_pv_field_ $dev2 pe_start $pv_align
-check_pv_field_ $dev3 pe_start $pv_align
-
-pvs --units k -o name,pe_start,vg_mda_size,vg_name
-
-# create backup and then restore $dev3
-vgcfgbackup -f $TESTDIR/bak-%s $vg
-pvcreate -ff -y --restorefile $TESTDIR/bak-$vg --uuid $pv3_uuid $dev3
-vgcfgrestore -f $TESTDIR/bak-$vg $vg
-
-# verify pe_start of $dev3
-check_pv_field_ $dev3 pe_start $pv_align
diff --git a/test/t-mirror-names.sh b/test/t-mirror-names.sh
deleted file mode 100644 (file)
index be6045f..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2007-2008 Red Hat, Inc. All rights reserved.
-# Copyright (C) 2007-2008 NEC Corporation
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-test_description="check namings of mirrored LV"
-
-. ./test-utils.sh
-
-# ---------------------------------------------------------------------
-# Utilities
-
-lv_devices_() {
-  local d
-  local lv=$1
-  shift
-  local devices=$*
-
-  local devs=$(lvs -a -odevices --noheadings $lv | sed 's/([0-9]*)//g' |
-               sed 's/ //g' | sed 's/,/ /g')
-
-  for d in $devs; do
-    (echo $devices | grep -q $d)  || return 1
-    devices=$(echo $devices | sed "s/$d//")
-  done
-
-  [ "$(echo $devices | sed 's/ //g')" = "" ]
-}
-
-lv_mirror_log_() {
-  local lv=$1
-
-  echo $(lvs -a -omirror_log --noheadings $lv | sed 's/ //g')
-}
-
-lv_convert_lv_() {
-  local lv=$1
-
-  echo $(lvs -a -oconvert_lv --noheadings $lv | sed 's/ //g')
-}
-
-# ---------------------------------------------------------------------
-# Initialize PVs and VGs
-
-aux prepare_vg 5 80
-
-# ---------------------------------------------------------------------
-# Common environment setup/cleanup for each sub testcases
-
-prepare_lvs_() {
-       lvremove -ff $vg
-       if dmsetup table|grep $vg; then
-               echo "ERROR: lvremove did leave some some mappings in DM behind!"
-               return 1
-       fi
-  :
-}
-
-check_and_cleanup_lvs_() {
-  lvs -a -o+devices $vg 
-  lvremove -ff $vg
-       if dmsetup table|grep $vg; then
-               echo "ERROR: lvremove did leave some some mappings in DM behind!"
-               return 1
-       fi
-}
-
-prepare_lvs_ 
-check_and_cleanup_lvs_
-
-# ---------------------------------------------------------------------
-# basic
-
-#COMM "init: lvcreate" 
-prepare_lvs_
-
-#COMM "mirror images are ${lv1}_mimage_x"
-lvcreate -l2 -m1 -n $lv1 $vg 
-lv_devices_ $vg/$lv1 "$lv1"_mimage_0 "$lv1"_mimage_1
-
-#COMM "mirror log is ${lv1}_mlog"
-lv_mirror_log_ $vg/$lv1 "$lv1"_mlog
-
-# "cleanup" 
-check_and_cleanup_lvs_
-
-#COMM "mirror with name longer than 22 characters (bz221322)"
-name="LVwithanamelogerthan22characters_butidontwonttocounthem"
-lvcreate -m1 -l2 -n"$name" $vg
-lvs $vg/"$name"
-check_and_cleanup_lvs_
-
-# ---------------------------------------------------------------------
-# lvrename
-
-#COMM "init: lvrename" 
-prepare_lvs_
-
-#COMM "renamed mirror names: $lv1 to $lv2" 
-lvcreate -l2 -m1 -n $lv1 $vg 
-lvrename $vg/$lv1 $vg/$lv2 
-lv_devices_ $vg/$lv2 "$lv2"_mimage_0 "$lv2"_mimage_1 
-lv_mirror_log_ $vg/$lv2 "$lv2"_mlog
-
-#COMM "cleanup" 
-check_and_cleanup_lvs_
-
-# ---------------------------------------------------------------------
-# lvconvert
-
-#COMM "init: lvconvert" 
-prepare_lvs_
-
-#COMM "converting mirror names is ${lv1}_mimagetmp_2"
-lvcreate -l2 -m1 -n $lv1 $vg 
-lvconvert -m+1 -i+10 -b $vg/$lv1
-convlv=$(lv_convert_lv_ "$vg/$lv1") 
-test "$convlv" = "$lv1"_mimagetmp_2 
-lv_devices_ $vg/$lv1 "$convlv" "$lv1"_mimage_2 
-lv_devices_ "$vg/$convlv" "$lv1"_mimage_0 "$lv1"_mimage_1 
-loglv=$(lv_mirror_log_ "$vg/$convlv") 
-test "$loglv" = "$lv1"_mlog
-
-#COMM "mirror log name after re-adding is ${lv1}_mlog" \
-lvconvert --mirrorlog core $vg/$lv1 
-lvconvert --mirrorlog disk $vg/$lv1 
-convlv=$(lv_convert_lv_ "$vg/$lv1") 
-lv_devices_ $vg/$lv1 "$convlv" "$lv1"_mimage_2 
-lv_devices_ "$vg/$convlv" "$lv1"_mimage_0 "$lv1"_mimage_1 
-loglv=$(lv_mirror_log_ "$vg/$convlv") 
-test "$loglv" = "$lv1"_mlog
-
-#COMM "renamed converting mirror names: $lv1 to $lv2" \
-lvrename $vg/$lv1 $vg/$lv2 
-convlv=$(lv_convert_lv_ "$vg/$lv2") 
-lv_devices_ $vg/$lv2 "$convlv" "$lv2"_mimage_2 
-lv_devices_ "$vg/$convlv" "$lv2"_mimage_0 "$lv2"_mimage_1 
-loglv=$(lv_mirror_log_ "$vg/$convlv") 
-test "$loglv" = "$lv2"_mlog
-
-#COMM "cleanup" 
-check_and_cleanup_lvs_
-
-# Temporary mirror log should have "_mlogtmp_<n>" suffix
-# but currently lvconvert doesn't have an option to add the log.
-# If such feature is added in future, a test for that should
-# be added.
-
-# ---------------------------------------------------------------------
diff --git a/test/t-mirror-vgreduce-removemissing.sh b/test/t-mirror-vgreduce-removemissing.sh
deleted file mode 100755 (executable)
index 0f6a8b0..0000000
+++ /dev/null
@@ -1,421 +0,0 @@
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-# Copyright (C) 2007 NEC Corporation
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-test_description="ensure that 'vgreduce --removemissing' works on mirrored LV"
-
-. ./test-utils.sh
-
-lv_is_on_ ()
-{
-       local lv=$vg/$1
-       shift
-       local pvs=$*
-
-       echo "Check if $lv is exactly on PVs $pvs"
-       rm -f out1 out2
-       echo $pvs | sed 's/ /\n/g' | sort | uniq > out1
-
-       lvs -a -o+devices $lv
-       lvs -a -odevices --noheadings $lv | \
-       sed 's/([^)]*)//g; s/[ ,]/\n/g' | sort | uniq > out2
-
-       diff --ignore-blank-lines out1 out2
-}
-
-mimages_are_on_ ()
-{
-       local lv=$1
-       shift
-       local pvs="$*"
-       local mimages
-       local i
-
-       echo "Check if mirror images of $lv are on PVs $pvs"
-       rm -f out1 out2
-       echo $pvs | sed 's/ /\n/g' | sort | uniq > out1
-
-       mimages=$(lvs --noheadings -a -o lv_name $vg | grep "${lv}_mimage_" | \
-               sed 's/\[//g; s/\]//g')
-       for i in $mimages; do
-               echo "Checking $vg/$i"
-               lvs -a -o+devices $vg/$i
-               lvs -a -odevices --noheadings $vg/$i | \
-                       sed 's/([^)]*)//g; s/ //g; s/,/ /g' | sort | uniq >> out2
-       done
-
-       diff --ignore-blank-lines out1 out2
-}
-
-mirrorlog_is_on_()
-{
-       local lv="$1"_mlog
-       shift
-       lv_is_on_ $lv $*
-}
-
-lv_is_linear_()
-{
-       echo "Check if $1 is linear LV (i.e. not a mirror)"
-       lvs -o stripes,attr --noheadings $vg/$1 | sed 's/ //g'
-       lvs -o stripes,attr --noheadings $vg/$1 | sed 's/ //g' | grep -q '^1-'
-}
-
-rest_pvs_()
-{
-       local index=$1
-       local num=$2
-       local rem=""
-       local n
-
-       for n in $(seq 1 $(($index - 1))) $(seq $(($index + 1)) $num); do
-               eval local dev=$\dev$n
-               rem="$rem $dev"
-       done
-
-       echo "$rem"
-}
-
-# ---------------------------------------------------------------------
-# Initialize PVs and VGs
-
-prepare_vg 5
-
-# ---------------------------------------------------------------------
-# Common environment setup/cleanup for each sub testcases
-
-prepare_lvs_()
-{
-       lvremove -ff $vg;
-       if dmsetup table|grep $vg; then
-               echo "ERROR: lvremove did leave some some mappings in DM behind!"
-               return 1
-       fi
-       :
-}
-
-check_and_cleanup_lvs_()
-{
-       lvs -a -o+devices $vg 
-       lvremove -ff $vg
-       if dmsetup table|grep $vg; then
-               echo "ERROR: lvremove did leave some some mappings in DM behind!"
-               return 1
-       fi
-}
-
-recover_vg_()
-{
-       enable_dev $* 
-       pvcreate -ff $* 
-       vgextend $vg $* 
-       check_and_cleanup_lvs_
-}
-
-#COMM "check environment setup/cleanup" 
-prepare_lvs_ 
-check_and_cleanup_lvs_
-
-# ---------------------------------------------------------------------
-# one of mirror images has failed
-
-#COMM "basic: fail the 2nd mirror image of 2-way mirrored LV"
-prepare_lvs_
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev3:0
-lvchange -an $vg/$lv1
-aux mimages_are_on_ $lv1 $dev1 $dev2
-mirrorlog_is_on_ $lv1 $dev3
-disable_dev $dev2
-vgreduce --removemissing --force $vg
-lv_is_linear_ $lv1
-lv_is_on_ $lv1 $dev1
-
-# "cleanup"
-recover_vg_ $dev2
-
-# ---------------------------------------------------------------------
-# LV has 3 images in flat,
-# 1 out of 3 images fails
-
-#COMM test_3way_mirror_fail_1_ <PV# to fail>
-test_3way_mirror_fail_1_()
-{
-       local index=$1
-
-       lvcreate -l2 -m2 -n $lv1 $vg $dev1 $dev2 $dev3 $dev4:0
-       lvchange -an $vg/$lv1
-       aux mimages_are_on_ $lv1 $dev1 $dev2 $dev3
-       mirrorlog_is_on_ $lv1 $dev4
-       eval disable_dev \$dev$index
-       vgreduce --removemissing --force $vg
-       lvs -a -o+devices $vg
-       mimages_are_on_ $lv1 $(rest_pvs_ $index 3)
-       mirrorlog_is_on_ $lv1 $dev4
-}
-
-for n in $(seq 1 3); do
-       #COMM fail mirror image $(($n - 1)) of 3-way mirrored LV"
-       prepare_lvs_
-       test_3way_mirror_fail_1_ $n
-       eval recover_vg_ \$dev$n
-done
-
-# ---------------------------------------------------------------------
-# LV has 3 images in flat,
-# 2 out of 3 images fail
-
-#COMM test_3way_mirror_fail_2_ <PV# NOT to fail>
-test_3way_mirror_fail_2_()
-{
-       local index=$1
-
-       lvcreate -l2 -m2 -n $lv1 $vg $dev1 $dev2 $dev3 $dev4:0
-       lvchange -an $vg/$lv1
-       mimages_are_on_ $lv1 $dev1 $dev2 $dev3
-       mirrorlog_is_on_ $lv1 $dev4
-       rest_pvs_ $index 3
-       disable_dev $(rest_pvs_ $index 3)
-       vgreduce --force --removemissing $vg
-       lvs -a -o+devices $vg
-       aux lv_is_linear_ $lv1
-       eval lv_is_on_ $lv1 \$dev$n
-}
-
-for n in $(seq 1 3); do
-       #COMM fail mirror images other than mirror image $(($n - 1)) of 3-way mirrored LV
-       prepare_lvs_
-       test_3way_mirror_fail_2_ $n
-       recover_vg_ $(rest_pvs_ $n 3)
-done
-
-# ---------------------------------------------------------------------
-# LV has 4 images, 1 of them is in the temporary mirror for syncing.
-# 1 out of 4 images fails
-
-#COMM test_3way_mirror_plus_1_fail_1_ <PV# to fail>
-test_3way_mirror_plus_1_fail_1_()
-{
-       local index=$1
-
-       lvcreate -l2 -m2 -n $lv1 $vg $dev1 $dev2 $dev3 $dev5:0
-       lvchange -an $vg/$lv1 
-       lvconvert -m+1 $vg/$lv1 $dev4 
-       mimages_are_on_ $lv1 $dev1 $dev2 $dev3 $dev4 
-       mirrorlog_is_on_ $lv1 $dev5 
-       eval disable_dev \$dev$n 
-       vgreduce --removemissing --force $vg 
-       lvs -a -o+devices $vg 
-       mimages_are_on_ $lv1 $(rest_pvs_ $index 4) 
-       mirrorlog_is_on_ $lv1 $dev5
-}
-
-for n in $(seq 1 4); do
-       #COMM "fail mirror image $(($n - 1)) of 4-way (1 converting) mirrored LV"
-       prepare_lvs_
-       test_3way_mirror_plus_1_fail_1_ $n
-       eval recover_vg_ \$dev$n
-done
-
-# ---------------------------------------------------------------------
-# LV has 4 images, 1 of them is in the temporary mirror for syncing.
-# 3 out of 4 images fail
-
-#COMM test_3way_mirror_plus_1_fail_3_ <PV# NOT to fail>
-test_3way_mirror_plus_1_fail_3_()
-{
-       local index=$1
-
-       lvcreate -l2 -m2 -n $lv1 $vg $dev1 $dev2 $dev3 $dev5:0
-       lvchange -an $vg/$lv1 
-       lvconvert -m+1 $vg/$lv1 $dev4 
-       mimages_are_on_ $lv1 $dev1 $dev2 $dev3 $dev4 
-       mirrorlog_is_on_ $lv1 $dev5 
-       disable_dev $(rest_pvs_ $index 4) 
-       vgreduce --removemissing --force $vg 
-       lvs -a -o+devices $vg 
-       eval local dev=\$dev$n
-       mimages_are_on_ $lv1 $dev || lv_is_on_ $lv1 $dev
-       not mirrorlog_is_on_ $lv1 $dev5
-}
-
-for n in $(seq 1 4); do
-       #COMM "fail mirror images other than mirror image $(($n - 1)) of 4-way (1 converting) mirrored LV"
-       prepare_lvs_
-       test_3way_mirror_plus_1_fail_3_ $n
-       recover_vg_ $(rest_pvs_ $n 4)
-done
-
-# ---------------------------------------------------------------------
-# LV has 4 images, 2 of them are in the temporary mirror for syncing.
-# 1 out of 4 images fail
-
-# test_2way_mirror_plus_2_fail_1_ <PV# to fail>
-test_2way_mirror_plus_2_fail_1_()
-{
-       local index=$1
-
-       lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev5:0
-       lvchange -an $vg/$lv1 
-       lvconvert -m+2 $vg/$lv1 $dev3 $dev4 
-       mimages_are_on_ $lv1 $dev1 $dev2 $dev3 $dev4 
-       mirrorlog_is_on_ $lv1 $dev5 
-       eval disable_dev \$dev$n 
-       vgreduce --removemissing --force $vg 
-       lvs -a -o+devices $vg 
-       mimages_are_on_ $lv1 $(rest_pvs_ $index 4) 
-       mirrorlog_is_on_ $lv1 $dev5
-}
-
-for n in $(seq 1 4); do
-       #COMM "fail mirror image $(($n - 1)) of 4-way (2 converting) mirrored LV" 
-       prepare_lvs_ 
-       test_2way_mirror_plus_2_fail_1_ $n
-       eval recover_vg_ \$dev$n
-done
-
-# ---------------------------------------------------------------------
-# LV has 4 images, 2 of them are in the temporary mirror for syncing.
-# 3 out of 4 images fail
-
-# test_2way_mirror_plus_2_fail_3_ <PV# NOT to fail>
-test_2way_mirror_plus_2_fail_3_()
-{
-       local index=$1
-
-       lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev5:0
-       lvchange -an $vg/$lv1 
-       lvconvert -m+2 $vg/$lv1 $dev3 $dev4 
-       mimages_are_on_ $lv1 $dev1 $dev2 $dev3 $dev4 
-       mirrorlog_is_on_ $lv1 $dev5 
-       disable_dev $(rest_pvs_ $index 4) 
-       vgreduce --removemissing --force $vg 
-       lvs -a -o+devices $vg 
-       eval local dev=\$dev$n
-       mimages_are_on_ $lv1 $dev || lv_is_on_ $lv1 $dev
-       not mirrorlog_is_on_ $lv1 $dev5
-}
-
-for n in $(seq 1 4); do
-       #COMM "fail mirror images other than mirror image $(($n - 1)) of 4-way (2 converting) mirrored LV"
-       prepare_lvs_
-       test_2way_mirror_plus_2_fail_3_ $n
-       recover_vg_ $(rest_pvs_ $n 4)
-done
-
-# ---------------------------------------------------------------------
-# log device is gone (flat mirror and stacked mirror)
-
-#COMM "fail mirror log of 2-way mirrored LV" 
-prepare_lvs_ 
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev5:0
-lvchange -an $vg/$lv1 
-mimages_are_on_ $lv1 $dev1 $dev2 
-mirrorlog_is_on_ $lv1 $dev5 
-disable_dev $dev5 
-vgreduce --removemissing --force $vg 
-mimages_are_on_ $lv1 $dev1 $dev2 
-not mirrorlog_is_on_ $lv1 $dev5
-recover_vg_ $dev5
-
-#COMM "fail mirror log of 3-way (1 converting) mirrored LV" 
-prepare_lvs_ 
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev5:0
-lvchange -an $vg/$lv1 
-lvconvert -m+1 $vg/$lv1 $dev3 
-mimages_are_on_ $lv1 $dev1 $dev2 $dev3 
-mirrorlog_is_on_ $lv1 $dev5 
-disable_dev $dev5 
-vgreduce --removemissing --force $vg 
-mimages_are_on_ $lv1 $dev1 $dev2 $dev3 
-not mirrorlog_is_on_ $lv1 $dev5
-recover_vg_ $dev5
-
-# ---------------------------------------------------------------------
-# all images are gone (flat mirror and stacked mirror)
-
-#COMM "fail all mirror images of 2-way mirrored LV"
-prepare_lvs_ 
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev5:0
-lvchange -an $vg/$lv1 
-mimages_are_on_ $lv1 $dev1 $dev2 
-mirrorlog_is_on_ $lv1 $dev5 
-disable_dev $dev1 $dev2 
-vgreduce --removemissing --force $vg 
-not lvs $vg/$lv1
-recover_vg_ $dev1 $dev2
-
-#COMM "fail all mirror images of 3-way (1 converting) mirrored LV"
-prepare_lvs_ 
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev5:0
-lvchange -an $vg/$lv1 
-lvconvert -m+1 $vg/$lv1 $dev3 
-mimages_are_on_ $lv1 $dev1 $dev2 $dev3 
-mirrorlog_is_on_ $lv1 $dev5 
-disable_dev $dev1 $dev2 $dev3 
-vgreduce --removemissing --force $vg 
-not lvs $vg/$lv1
-recover_vg_ $dev1 $dev2 $dev3
-
-# ---------------------------------------------------------------------
-# Multiple LVs
-
-#COMM "fail a mirror image of one of mirrored LV"
-prepare_lvs_ 
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev5:0
-lvchange -an $vg/$lv1 
-lvcreate -l2 -m1 -n $lv2 $vg $dev3 $dev4 $dev5:1 
-lvchange -an $vg/$lv2 
-mimages_are_on_ $lv1 $dev1 $dev2 
-mimages_are_on_ $lv2 $dev3 $dev4 
-mirrorlog_is_on_ $lv1 $dev5 
-mirrorlog_is_on_ $lv2 $dev5 
-disable_dev $dev2 
-vgreduce --removemissing --force $vg 
-mimages_are_on_ $lv2 $dev3 $dev4 
-mirrorlog_is_on_ $lv2 $dev5 
-lv_is_linear_ $lv1 
-lv_is_on_ $lv1 $dev1
-recover_vg_ $dev2
-
-#COMM "fail mirror images, one for each mirrored LV"
-prepare_lvs_ 
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev5:0
-lvchange -an $vg/$lv1 
-lvcreate -l2 -m1 -n $lv2 $vg $dev3 $dev4 $dev5:1 
-lvchange -an $vg/$lv2 
-mimages_are_on_ $lv1 $dev1 $dev2 
-mimages_are_on_ $lv2 $dev3 $dev4 
-mirrorlog_is_on_ $lv1 $dev5 
-mirrorlog_is_on_ $lv2 $dev5 
-disable_dev $dev2 
-disable_dev $dev4 
-vgreduce --removemissing --force $vg 
-lv_is_linear_ $lv1 
-lv_is_on_ $lv1 $dev1 
-lv_is_linear_ $lv2 
-lv_is_on_ $lv2 $dev3
-recover_vg_ $dev2 $dev4
-
-# ---------------------------------------------------------------------
-# no failure
-
-#COMM "no failures"
-prepare_lvs_ 
-lvcreate -l2 -m1 -n $lv1 $vg $dev1 $dev2 $dev5:0
-lvchange -an $vg/$lv1 
-mimages_are_on_ $lv1 $dev1 $dev2 
-mirrorlog_is_on_ $lv1 $dev5 
-vgreduce --removemissing --force $vg 
-mimages_are_on_ $lv1 $dev1 $dev2 
-mirrorlog_is_on_ $lv1 $dev5
-check_and_cleanup_lvs_
-
-# ---------------------------------------------------------------------
-
diff --git a/test/t-nomda-missing.sh b/test/t-nomda-missing.sh
deleted file mode 100644 (file)
index fb0b882..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/bin/bash
-
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-prepare_devs 4
-pvcreate $dev1 $dev2
-pvcreate --metadatacopies 0 $dev3 $dev4
-vgcreate -c n $vg $dev1 $dev2 $dev3 $dev4
-
-lvcreate -l1 -n linear1 $vg $dev1
-lvcreate -l1 -n linear2 $vg $dev2
-lvcreate -l2 -n linear12 $vg $dev1:4 $dev2:4
-
-lvcreate -l1 -n origin1 $vg $dev1
-lvcreate -s $vg/origin1 -l1 -n s_napshot2 $dev2
-
-lvcreate -l1 -m1 -n mirror12 --mirrorlog core $vg $dev1 $dev2
-lvcreate -l1 -m1 -n mirror123 $vg $dev1 $dev2 $dev3
-
-vgchange -a n $vg
-disable_dev $dev1
-not vgchange -a y $vg
-not vgck $vg
-
-check inactive $vg linear1
-check active $vg linear2
-check inactive $vg origin1
-check inactive $vg s_napshot2
-check inactive $vg linear12
-check inactive $vg mirror12
-check inactive $vg mirror123
-
-vgchange -a n $vg
-enable_dev $dev1
-disable_dev $dev2
-not vgchange -a y $vg
-not vgck $vg
-
-check active $vg linear1
-check inactive $vg linear2
-check inactive $vg linear12
-check inactive $vg origin1
-check inactive $vg s_napshot2
-check inactive $vg mirror12
-check inactive $vg mirror123
-
-vgchange -a n $vg
-enable_dev $dev2
-disable_dev $dev3
-not vgchange -a y $vg
-not vgck $vg
-
-check active $vg origin1
-check active $vg s_napshot2
-check active $vg linear1
-check active $vg linear2
-check active $vg linear12
-check inactive $vg mirror123
-check active $vg mirror12
-
-vgchange -a n $vg
-enable_dev $dev3
-disable_dev $dev4
-vgchange -a y $vg
-not vgck $vg
-
-check active $vg origin1
-check active $vg s_napshot2
-check active $vg linear1
-check active $vg linear2
-check active $vg linear12
-check active $vg mirror12
-check active $vg mirror123
diff --git a/test/t-pool-labels.sh b/test/t-pool-labels.sh
deleted file mode 100755 (executable)
index 57f4f9a..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (C) 2007 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-# create the old GFS pool labeled linear devices
-create_pool_label_()
-{
-  # FIXME
-  # echo -e is bashism, dash builtin sh doesn't do \xNN in printf either
-  # printf comes from coreutils, and is probably not posix either
-  env printf "\x01\x16\x70\x06\x5f\xcf\xff\xb9\xf8\x24\x8apool1" | dd of=$2 bs=5 seek=1 conv=notrunc
-  env printf "\x04\x01\x03\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x0$1\x68\x01\x16\x70\x00\x00\x00\x00\x00\x06\x5f\xd0" | dd of=$2 bs=273 seek=1 conv=notrunc
-}
-
-env printf "" || exit 200 # skip if printf is not available
-
-aux prepare_devs 2
-
-create_pool_label_ 0 "$dev1"
-create_pool_label_ 1 "$dev2"
-
-# check that pvcreate fails without -ff on the pool device
-not pvcreate "$dev1"
-
-# check that vgdisplay and pvcreate -ff works with the pool device
-vgdisplay --config 'global { locking_type = 0 }'
-disable_dev "$dev2"
-# FIXME! since pool1 cannot be opened, vgdisplay gives error... should we say
-# "not" there instead, checking that it indeed does fail?
-vgdisplay --config 'global { locking_type = 0 }' || true
-pvcreate -ff -y "$dev1"
diff --git a/test/t-pv-range-overflow.sh b/test/t-pv-range-overflow.sh
deleted file mode 100755 (executable)
index 04674cb..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-# 'Ensure that pvmove diagnoses PE-range values 2^32 and larger.'
-
-. ./test-utils.sh
-
-aux prepare_vg 2
-
-lvcreate -L4 -n"$lv" $vg
-
-# Test for the bogus diagnostic reported in BZ 284771
-# http://bugzilla.redhat.com/284771.
-# 'run pvmove with an unrecognized LV name to show bad diagnostic'
-not pvmove -v -nbogus $dev1 $dev2 2> err
-grep "  Logical volume bogus not found." err
-
-# With lvm-2.02.28 and earlier, on a system with 64-bit "long int",
-# the PE range parsing code would accept values up to 2^64-1, but would
-# silently truncate them to int32_t.  I.e., $dev1:$(echo 2^32|bc) would be
-# treated just like $dev1:0.
-# 'run the offending pvmove command'
-not pvmove -v -n$lv $dev1:4294967296 $dev2
-
diff --git a/test/t-pvchange-usage.sh b/test/t-pvchange-usage.sh
deleted file mode 100755 (executable)
index 0f69249..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-# 'Test pvchange option values'
-
-. ./test-utils.sh
-
-aux prepare_devs 4
-
-for mda in 0 1 2 
-do
-# "setup pv with metadatacopies = $mda" 
-       pvcreate $dev4 
-       pvcreate --metadatacopies $mda $dev1 
-       vgcreate $vg1 $dev1 $dev4 
-
-# "pvchange adds/dels tag to pvs with metadatacopies = $mda " 
-       pvchange $dev1 --addtag test$mda 
-       check_pv_field_ $dev1 pv_tags test$mda 
-       pvchange $dev1 --deltag test$mda 
-       check_pv_field_ $dev1 pv_tags ""
-
-# "vgchange disable/enable allocation for pvs with metadatacopies = $mda (bz452982)"
-       pvchange $dev1 -x n 
-       check_pv_field_ $dev1 pv_attr  --  
-       pvchange $dev1 -x y 
-       check_pv_field_ $dev1 pv_attr  a- 
-
-# 'remove pv'
-       vgremove $vg1 
-       pvremove $dev1 $dev4
-done
-
-# "pvchange uuid"
-pvcreate --metadatacopies 0 $dev1 
-pvcreate --metadatacopies 2 $dev2 
-vgcreate $vg1 $dev1 $dev2 
-pvchange -u $dev1 
-pvchange -u $dev2 
-vg_validate_pvlv_counts_ $vg1 2 0 0
-pvchange -u --all
-vg_validate_pvlv_counts_ $vg1 2 0 0
-
-# "pvchange rejects uuid change under an active lv" 
-lvcreate -l 16 -i 2 -n $lv --alloc anywhere $vg1 
-vg_validate_pvlv_counts_ $vg1 2 1 0 
-not pvchange -u $dev1
-lvchange -an "$vg1"/"$lv" 
-pvchange -u $dev1
-
-# "cleanup" 
-lvremove -f "$vg1"/"$lv"
-vgremove $vg1
-
-# "pvchange reject --addtag to lvm1 pv"
-pvcreate -M1 $dev1 
-not pvchange $dev1 --addtag test
-
diff --git a/test/t-pvcreate-metadata0.sh b/test/t-pvcreate-metadata0.sh
deleted file mode 100755 (executable)
index 8447ce5..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-#
-# Testcase for bugzilla #450651
-# also checks that vgremove properly removes all lv devices in the right order
-#
-# 'Test pvcreate without metadata on all pvs'
-
-. ./test-utils.sh
-
-aux prepare_devs 2 128
-
-#lv_snap=$lv2
-pvcreate "$dev1"
-pvcreate --metadatacopies 0 "$dev2"
-
-# "check lv snapshot" 
-vgcreate -c n "$vg" "$dev1" "$dev2" 
-lvcreate -n "$lv" -l 60%FREE "$vg" 
-lvcreate -s -n $lv2 -l 10%FREE "$vg"/"$lv" 
-pvdisplay 
-lvdisplay
-vgremove -f "$vg"
diff --git a/test/t-pvcreate-operation-md.sh b/test/t-pvcreate-operation-md.sh
deleted file mode 100644 (file)
index cab63a0..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-# Copyright (C) 2009 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-# skip this test if mdadm or sfdisk (or others) aren't available
-which mdadm || exit 200
-which sfdisk || exit 200
-which perl || exit 200
-which awk || exit 200
-which cut || exit 200
-
-test -f /proc/mdstat && grep -q raid0 /proc/mdstat || \
-modprobe raid0 || exit 200
-
-. ./test-utils.sh
-
-prepare_lvmconf '[ "a|/dev/md.*|", "a/dev\/mapper\/.*$/", "r/.*/" ]'
-aux prepare_devs 2
-
-# Have MD use a non-standard name to avoid colliding with an existing MD device
-# - mdadm >= 3.0 requires that non-standard device names be in /dev/md/
-# - newer mdadm _completely_ defers to udev to create the associated device node
-mdadm_maj=$(mdadm --version 2>&1 | perl -pi -e 's|.* v(\d+).*|\1|')
-[ $mdadm_maj -ge 3 ] && \
-    mddev=/dev/md/md_lvm_test0 || \
-    mddev=/dev/md_lvm_test0
-
-cleanup_md() {
-    # sleeps offer hack to defeat: 'md: md127 still in use'
-    # see: https://bugzilla.redhat.com/show_bug.cgi?id=509908#c25
-    sleep 2
-    mdadm --stop $mddev || true
-    if [ -b "$mddev" ]; then
-        # mdadm doesn't always cleanup the device node
-       sleep 2
-       rm -f $mddev
-    fi
-}
-
-cleanup_md_and_teardown() {
-    cleanup_md
-    teardown
-}
-
-# create 2 disk MD raid0 array (stripe_width=128K)
-test -b "$mddev" && exit 200
-mdadm --create --metadata=1.0 $mddev --auto=md --level 0 --raid-devices=2 --chunk 64 $dev1 $dev2
-trap 'aux cleanup_md_and_teardown' EXIT # cleanup this MD device at the end of the test
-test -b "$mddev" || exit 200
-
-# Test alignment of PV on MD without any MD-aware or topology-aware detection
-# - should treat $mddev just like any other block device
-pv_align="1.00m"
-pvcreate --metadatasize 128k \
-    --config 'devices {md_chunk_alignment=0 data_alignment_detection=0 data_alignment_offset_detection=0}' \
-    $mddev
-check_pv_field_ $mddev pe_start $pv_align
-
-# Test md_chunk_alignment independent of topology-aware detection
-pv_align="1.00m"
-pvcreate --metadatasize 128k \
-    --config 'devices {data_alignment_detection=0 data_alignment_offset_detection=0}' \
-    $mddev
-check_pv_field_ $mddev pe_start $pv_align
-
-# Get linux minor version
-linux_minor=$(echo `uname -r` | cut -d'.' -f3 | cut -d'-' -f1)
-
-# Test newer topology-aware alignment detection
-# - first added to 2.6.31 but not "reliable" until 2.6.33
-if [ $linux_minor -ge 33 ]; then
-    pv_align="1.00m"
-    # optimal_io_size=131072, minimum_io_size=65536
-    pvcreate --metadatasize 128k \
-       --config 'devices { md_chunk_alignment=0 }' $mddev
-    check_pv_field_ $mddev pe_start $pv_align
-fi
-
-# partition MD array directly, depends on blkext in Linux >= 2.6.28
-if [ $linux_minor -ge 28 ]; then
-    # create one partition
-    sfdisk $mddev <<EOF
-,,83
-EOF
-    # make sure partition on MD is _not_ removed
-    # - tests partition -> parent lookup via sysfs paths
-    not pvcreate --metadatasize 128k $mddev
-
-    # verify alignment_offset is accounted for in pe_start
-    # - topology infrastructure is available in Linux >= 2.6.31
-    # - also tests partition -> parent lookup via sysfs paths
-
-    # Oh joy: need to lookup /sys/block/md127 rather than /sys/block/md_lvm_test0
-    mddev_maj_min=$(ls -lL $mddev | awk '{ print $5 $6 }' | perl -pi -e 's|,|:|')
-    mddev_p_sysfs_name=$(echo /sys/dev/block/${mddev_maj_min}/*p1)
-    base_mddev_p=`basename $mddev_p_sysfs_name`
-    mddev_p=/dev/${base_mddev_p}
-
-    # Checking for 'alignment_offset' in sysfs implies Linux >= 2.6.31
-    # but reliable alignment_offset support requires kernel.org Linux >= 2.6.33
-    sysfs_alignment_offset=/sys/dev/block/${mddev_maj_min}/${base_mddev_p}/alignment_offset
-    [ -f $sysfs_alignment_offset -a $linux_minor -ge 33 ] && \
-       alignment_offset=`cat $sysfs_alignment_offset` || \
-       alignment_offset=0
-
-    if [ $alignment_offset -gt 0 ]; then    
-        # default alignment is 1M, add alignment_offset
-       pv_align=$((1048576+$alignment_offset))B
-       pvcreate --metadatasize 128k $mddev_p
-       check_pv_field_ $mddev_p pe_start $pv_align "--units b"
-       pvremove $mddev_p
-    fi
-fi
-
-# Test newer topology-aware alignment detection w/ --dataalignment override
-if [ $linux_minor -ge 33 ]; then
-    cleanup_md
-    pvcreate -f $dev1
-    pvcreate -f $dev2
-
-    # create 2 disk MD raid0 array (stripe_width=2M)
-    test -b "$mddev" && exit 200
-    mdadm --create --metadata=1.0 $mddev --auto=md --level 0 --raid-devices=2 --chunk 1024 $dev1 $dev2
-    test -b "$mddev" || exit 200
-
-    # optimal_io_size=2097152, minimum_io_size=1048576
-    pv_align="2.00m"
-    pvcreate --metadatasize 128k \
-       --config 'devices { md_chunk_alignment=0 }' $mddev
-    check_pv_field_ $mddev pe_start $pv_align
-
-    # now verify pe_start alignment override using --dataalignment
-    pv_align="192.00k"
-    pvcreate --dataalignment 64k --metadatasize 128k \
-       --config 'devices { md_chunk_alignment=0 }' $mddev
-    check_pv_field_ $mddev pe_start $pv_align
-fi
diff --git a/test/t-pvcreate-operation.sh b/test/t-pvcreate-operation.sh
deleted file mode 100755 (executable)
index 2c94696..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-aux prepare_devs 4
-
-for mdatype in 1 2
-do
-# pvcreate (lvm$mdatype) refuses to overwrite an mounted filesystem (bz168330)
-       test ! -d $TESTDIR/mnt && mkdir $TESTDIR/mnt
-       if mke2fs $dev1; then
-               mount $dev1 $TESTDIR/mnt
-               not pvcreate -M$mdatype $dev1 2>err
-               grep "Can't open $dev1 exclusively.  Mounted filesystem?" err
-               umount $dev1
-       fi
-
-# pvcreate (lvm$mdatype) succeeds when run repeatedly (pv not in a vg) (bz178216)
-    pvcreate -M$mdatype $dev1
-    pvcreate -M$mdatype $dev1
-    pvremove -f $dev1
-
-# pvcreate (lvm$mdatype) fails when PV belongs to VG" \
-    pvcreate -M$mdatype $dev1
-    vgcreate -M$mdatype $vg1 $dev1
-    not pvcreate -M$mdatype $dev1
-
-    vgremove -f $vg1
-    pvremove -f $dev1
-
-# pvcreate (lvm$mdatype) fails when PV1 does and PV2 does not belong to VG
-    pvcreate -M$mdatype $dev1
-    pvcreate -M$mdatype $dev2
-    vgcreate -M$mdatype $vg1 $dev1
-
-# pvcreate a second time on $dev2 and $dev1
-    not pvcreate -M$mdatype $dev2 $dev1
-
-    vgremove -f $vg1
-    pvremove -f $dev2
-    pvremove -f $dev1
-
-# NOTE: Force pvcreate after test completion to ensure clean device
-#test_expect_success \
-#  "pvcreate (lvm$mdatype) fails on md component device" \
-#  'mdadm -C -l raid0 -n 2 /dev/md0 $dev1 $dev2 &&
-#   pvcreate -M$mdatype $dev1;
-#   status=$?; echo status=$status; test $status != 0 &&
-#   mdadm --stop /dev/md0 &&
-#   pvcreate -ff -y -M$mdatype $dev1 $dev2 &&
-#   pvremove -f $dev1 $dev2'
-done
-
-# pvcreate (lvm2) fails without -ff when PV with metadatacopies=0 belongs to VG
-pvcreate --metadatacopies 0 $dev1
-pvcreate --metadatacopies 1 $dev2
-vgcreate $vg1 $dev1 $dev2
-not pvcreate $dev1
-vgremove -f $vg1
-pvremove -f $dev2
-pvremove -f $dev1
-
-# pvcreate (lvm2) succeeds with -ff when PV with metadatacopies=0 belongs to VG
-pvcreate --metadatacopies 0 $dev1 
-pvcreate --metadatacopies 1 $dev2
-vgcreate $vg1 $dev1 $dev2 
-pvcreate -ff -y $dev1 
-vgreduce --removemissing $vg1 
-vgremove -ff $vg1 
-pvremove -f $dev2 
-pvremove -f $dev1
-
-for i in 0 1 2 3
-do
-# pvcreate (lvm2) succeeds writing LVM label at sector $i
-    pvcreate --labelsector $i $dev1
-    dd if=$dev1 bs=512 skip=$i count=1 2>/dev/null | strings | grep -q LABELONE;
-    pvremove -f $dev1
-done
-
-# pvcreate (lvm2) fails writing LVM label at sector 4
-not pvcreate --labelsector 4 $dev1
-
-backupfile=$PREFIX.mybackupfile
-uuid1=freddy-fred-fred-fred-fred-fred-freddy
-uuid2=freddy-fred-fred-fred-fred-fred-fredie
-bogusuuid=fred
-
-# pvcreate rejects uuid option with less than 32 characters
-not pvcreate --norestorefile --uuid $bogusuuid $dev1
-
-# pvcreate rejects uuid option without restorefile
-not pvcreate --uuid $uuid1 $dev1
-
-# pvcreate rejects uuid already in use
-pvcreate --norestorefile --uuid $uuid1 $dev1
-not pvcreate --norestorefile --uuid $uuid1 $dev2
-
-# pvcreate rejects non-existent file given with restorefile
-not pvcreate --uuid $uuid1 --restorefile $backupfile $dev1
-
-# pvcreate rejects restorefile with uuid not found in file
-pvcreate --norestorefile --uuid $uuid1 $dev1
-vgcfgbackup -f $backupfile
-not pvcreate --uuid $uuid2 --restorefile $backupfile $dev2
-
-# pvcreate wipes swap signature when forced
-dd if=/dev/zero of=$dev1 bs=1024 count=64
-mkswap $dev1
-blkid -c /dev/null $dev1 | grep "swap"
-pvcreate -f $dev1
-# blkid cannot make up its mind whether not finding anything it knows is a failure or not
-(blkid -c /dev/null $dev1 || true) | not grep "swap"
diff --git a/test/t-pvcreate-usage.sh b/test/t-pvcreate-usage.sh
deleted file mode 100755 (executable)
index 35dc1c0..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-test_description='Test pvcreate option values'
-PAGESIZE=$(getconf PAGESIZE)
-
-. ./test-utils.sh
-
-aux prepare_devs 4
-
-#COMM 'pvcreate rejects negative setphysicalvolumesize'
-not pvcreate --setphysicalvolumesize -1024 $dev1
-
-#COMM 'pvcreate rejects negative metadatasize'
-not pvcreate --metadatasize -1024 $dev1
-
-# x. metadatasize 0, defaults to 255
-# FIXME: unable to check default value, not in reporting cmds
-# should default to 255 according to code
-#   check_pv_field_ pv_mda_size 255 
-#COMM 'pvcreate accepts metadatasize 0'
-pvcreate --metadatasize 0 $dev1
-pvremove $dev1
-
-#Verify vg_mda_size is smaller pv_mda_size
-pvcreate --metadatasize 512k $dev1
-pvcreate --metadatasize 96k $dev2
-vgcreate $vg $dev1 $dev2
-compare_two_fields_ vgs $vg vg_mda_size pvs $dev2 pv_mda_size
-vgremove -ff $vg
-
-# x. metadatasize too large
-# For some reason we allow this, even though there's no room for data?
-##COMM  'pvcreate rejects metadatasize too large' 
-#not pvcreate --metadatasize 100000000000000 $dev1
-
-#COMM 'pvcreate rejects metadatacopies < 0'
-not pvcreate --metadatacopies -1 $dev1
-
-#COMM 'pvcreate accepts metadatacopies = 0, 1, 2'
-for j in metadatacopies pvmetadatacopies
-do
-pvcreate --$j 0 $dev1
-pvcreate --$j 1 $dev2
-pvcreate --$j 2 $dev3
-check_pv_field_ $dev1 pv_mda_count 0
-check_pv_field_ $dev2 pv_mda_count 1
-check_pv_field_ $dev3 pv_mda_count 2
-pvremove $dev1 
-pvremove $dev2 
-pvremove $dev3
-done
-
-#COMM 'pvcreate rejects metadatacopies > 2'
-not pvcreate --metadatacopies 3 $dev1
-
-#COMM 'pvcreate rejects invalid device'
-not pvcreate $dev1bogus
-
-#COMM 'pvcreate rejects labelsector < 0'
-not pvcreate --labelsector -1 $dev1
-
-#COMM 'pvcreate rejects labelsector > 1000000000000'
-not pvcreate --labelsector 1000000000000 $dev1
-
-# other possibilites based on code inspection (not sure how hard)
-# x. device too small (min of 512 * 1024 KB)
-# x. device filtered out
-# x. unable to open /dev/urandom RDONLY
-# x. device too large (pe_count > UINT32_MAX)
-# x. device read-only
-# x. unable to open device readonly
-# x. BLKGETSIZE64 fails
-# x. set size to value inconsistent with device / PE size
-
-#COMM 'pvcreate basic dataalignment sanity checks'
-not pvcreate --dataalignment -1 $dev1
-not pvcreate -M 1 --dataalignment 1 $dev1
-not pvcreate --dataalignment 1e $dev1
-
-#COMM 'pvcreate always rounded up to page size for start of device'
-#pvcreate --metadatacopies 0 --dataalignment 1 $dev1
-# amuse shell experts
-#check_pv_field_ $dev1 pe_start $(($(getconf PAGESIZE)/1024))".00k"
-
-#COMM 'pvcreate sets data offset directly'
-pvcreate --dataalignment 512k $dev1
-check_pv_field_ $dev1 pe_start 512.00k
-
-#COMM 'vgcreate/vgremove do not modify data offset of existing PV'
-vgcreate $vg $dev1  --config 'devices { data_alignment = 1024 }'
-check_pv_field_ $dev1 pe_start 512.00k
-vgremove $vg --config 'devices { data_alignment = 1024 }'
-check_pv_field_ $dev1 pe_start 512.00k
-
-#COMM 'pvcreate sets data offset next to mda area'
-pvcreate --metadatasize 100k --dataalignment 100k $dev1
-check_pv_field_ $dev1 pe_start 200.00k
-
-# metadata area start is aligned according to pagesize
-# pagesize should be 64k or 4k ...
-if [ $PAGESIZE -eq 65536 ] ; then
-       pv_align="192.50k"
-else
-       pv_align="133.00k"
-fi
-
-pvcreate --metadatasize 128k --dataalignment 3.5k $dev1
-check_pv_field_ $dev1 pe_start $pv_align
-
-pvcreate --metadatasize 128k --metadatacopies 2 --dataalignment 3.5k $dev1
-check_pv_field_ $dev1 pe_start $pv_align
-
-# data area is aligned to 1M by default,
-# data area start is shifted by the specified alignment_offset
-pv_align="1052160B" # 1048576 + (7*512)
-pvcreate --metadatasize 128k --dataalignmentoffset 7s $dev1
-check_pv_field_ $dev1 pe_start $pv_align "--units b"
-
-# 2nd metadata area is created without problems when
-# data area start is shifted by the specified alignment_offset
-pvcreate --metadatasize 128k --metadatacopies 2 --dataalignmentoffset 7s $dev1
-check_pv_field_ $dev1 pv_mda_count 2
-# FIXME: compare start of 2nd mda with and without --dataalignmentoffset
-
-#COMM 'pv with LVM1 compatible data alignment can be convereted'
-#compatible == LVM1_PE_ALIGN == 64k
-pvcreate --dataalignment 256k $dev1
-vgcreate -s 1m $vg $dev1
-vgconvert -M1 $vg
-vgconvert -M2 $vg
-check_pv_field_ $dev1 pe_start 256.00k
-vgremove $vg
-
-#COMM 'pv with LVM1 incompatible data alignment cannot be convereted'
-pvcreate --dataalignment 10k $dev1
-vgcreate -s 1m $vg $dev1
-not vgconvert -M1 $vg
-vgremove $vg
-
-#COMM 'vgcfgrestore allows pe_start=0'
-#basically it produces nonsense, but it tests vgcfgrestore,
-#not that final cfg is usable...
-pvcreate --metadatacopies 0 $dev1
-pvcreate $dev2
-vgcreate $vg $dev1 $dev2
-vgcfgbackup -f "$(pwd)/backup.$$" $vg
-sed 's/pe_start = [0-9]*/pe_start = 0/' "$(pwd)/backup.$$" > "$(pwd)/backup.$$1"
-vgcfgrestore -f "$(pwd)/backup.$$1" $vg
-check_pv_field_ $dev1 pe_start 0
-check_pv_field_ $dev2 pe_start 0
-vgremove $vg
-
-echo test pvcreate --metadataignore
-for pv_in_vg in 1 0; do
-for mdacp in 1 2; do
-for ignore in y n; do
-       echo pvcreate --metadataignore has proper mda_count and mda_used_count
-       pvcreate --metadatacopies $mdacp --metadataignore $ignore $dev1 $dev2
-       check_pv_field_ $dev1 pv_mda_count $mdacp
-       check_pv_field_ $dev2 pv_mda_count $mdacp
-       if [ $ignore = y ]; then
-               check_pv_field_ $dev1 pv_mda_used_count 0
-               check_pv_field_ $dev2 pv_mda_used_count 0
-       else
-               check_pv_field_ $dev1 pv_mda_used_count $mdacp
-               check_pv_field_ $dev2 pv_mda_used_count $mdacp
-       fi
-       echo vgcreate has proper vg_mda_count and vg_mda_used_count
-       if [ $pv_in_vg = 1 ]; then
-               vgcreate -c n "$vg" $dev1 $dev2
-               check_vg_field_ $vg vg_mda_count $(($mdacp * 2))
-               if [ $ignore = y ]; then
-                       check_vg_field_ $vg vg_mda_used_count 1
-               else
-                       check_vg_field_ $vg vg_mda_used_count $(($mdacp * 2))
-               fi
-               check_vg_field_ $vg vg_mda_copies unmanaged
-               vgremove $vg
-       fi
-done
-done
-done
diff --git a/test/t-pvmove-basic.sh b/test/t-pvmove-basic.sh
deleted file mode 100755 (executable)
index 44b533c..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-# Copyright (C) 2007 NEC Corporation
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-test_description="ensure that pvmove works with basic options"
-
-. ./test-utils.sh
-
-# ---------------------------------------------------------------------
-# Utilities
-
-lvdev_() {
-  echo "$DM_DEV_DIR/$1/$2"
-}
-
-lv_is_on_() {
-  local lv=$1 #allready vg/lv
-  shift 1
-  lvs -a -odevices --noheadings $lv | sed 's/,/\n/g' > out
-#is on all specified devs
-  for d in $*; do grep "$d(" out; done
-#isn't on any other dev (we are set -e remember)
-  for d in $*; do ! grep -v "$d(" out; done
-  return 0
-}
-
-save_dev_sum_() {
-  mkfs.ext3 $1 > /dev/null && md5sum $1 > md5.$(basename $1)
-}
-
-check_dev_sum_() {
-  md5sum $1 > md5.tmp && cmp md5.$(basename $1) md5.tmp
-}
-
-# ---------------------------------------------------------------------
-# Initialize PVs and VGs
-
-aux prepare_vg 5 80
-
-# ---------------------------------------------------------------------
-# Common environment setup/cleanup for each sub testcases
-
-prepare_lvs_() {
-  lvcreate -l2 -n $lv1 $vg $dev1 
-    lv_is_on_ $vg/$lv1 $dev1 
-  lvcreate -l9 -i3 -n $lv2 $vg $dev2 $dev3 $dev4 
-    lv_is_on_ $vg/$lv2 $dev2 $dev3 $dev4 
-  lvextend -l+2 $vg/$lv1 $dev2 
-    lv_is_on_ $vg/$lv1 $dev1 $dev2 
-  lvextend -l+2 $vg/$lv1 $dev3 
-    lv_is_on_ $vg/$lv1 $dev1 $dev2 $dev3 
-  lvextend -l+2 $vg/$lv1 $dev1 
-    lv_is_on_ $vg/$lv1 $dev1 $dev2 $dev3 $dev1 
-  lvcreate -l1 -n $lv3 $vg $dev2 
-    lv_is_on_ $vg/$lv3 $dev2 
-  save_dev_sum_ $(lvdev_ $vg $lv1) 
-  save_dev_sum_ $(lvdev_ $vg $lv2) 
-  save_dev_sum_ $(lvdev_ $vg $lv3) 
-  lvs -a -o devices --noheadings $vg/$lv1 > ${lv1}_devs 
-  lvs -a -o devices --noheadings $vg/$lv2 > ${lv2}_devs 
-  lvs -a -o devices --noheadings $vg/$lv3 > ${lv3}_devs
-}
-
-lv_not_changed_() {
-  lvs -a -o devices --noheadings $1 > out
-  diff $(basename $1)_devs out
-}
-
-check_and_cleanup_lvs_() {
-  lvs -a -o+devices $vg
-  check_dev_sum_ $(lvdev_ $vg $lv1)
-  check_dev_sum_ $(lvdev_ $vg $lv2)
-  check_dev_sum_ $(lvdev_ $vg $lv3)
-  lvs -a -o name $vg > out && ! grep ^pvmove out
-  lvremove -ff $vg
-       if ! dmsetup table|not grep $vg; then
-               echo "ERROR: lvremove did leave some some mappings in DM behind!" && \
-                       return 1
-       fi
-       :
-}
-
-#COMM "check environment setup/cleanup"
-prepare_lvs_
-check_and_cleanup_lvs_
-
-# ---------------------------------------------------------------------
-# pvmove tests
-
-# ---
-# filter by LV
-
-#COMM "only specified LV is moved: from pv2 to pv5 only for lv1"
-prepare_lvs_ 
-pvmove -i1 -n $vg/$lv1 $dev2 $dev5 
-lv_is_on_ $vg/$lv1 $dev1 $dev5 $dev3 $dev1 
-lv_not_changed_ $vg/$lv2 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-# ---
-# segments in a LV
-
-#COMM "the 1st seg of 3-segs LV is moved: from pv1 of lv1 to pv4"
-prepare_lvs_ 
-pvmove -i1 -n $vg/$lv1 $dev1 $dev4 
-lv_is_on_ $vg/$lv1 $dev4 $dev2 $dev3 $dev4 
-lv_not_changed_ $vg/$lv2 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-#COMM "the 2nd seg of 3-segs LV is moved: from pv2 of lv1 to pv4"
-prepare_lvs_ 
-pvmove -i1 -n $vg/$lv1 $dev2 $dev4 
-lv_is_on_ $vg/$lv1 $dev1 $dev4 $dev3 $dev1 
-lv_not_changed_ $vg/$lv2 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-#COMM "the 3rd seg of 3-segs LV is moved: from pv3 of lv1 to pv4"
-prepare_lvs_ 
-pvmove -i1 -n $vg/$lv1 $dev3 $dev4 
-lv_is_on_ $vg/$lv1 $dev1 $dev2 $dev4 $dev1 
-lv_not_changed_ $vg/$lv2 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-# ---
-# multiple LVs matching
-
-#COMM "1 out of 3 LVs is moved: from pv4 to pv5"
-prepare_lvs_ 
-pvmove -i1 $dev4 $dev5 
-lv_not_changed_ $vg/$lv1 
-lv_is_on_ $vg/$lv2 $dev2 $dev3 $dev5 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-#COMM "2 out of 3 LVs are moved: from pv3 to pv5"
-prepare_lvs_ 
-pvmove -i1 $dev3 $dev5 
-lv_is_on_ $vg/$lv1 $dev1 $dev2 $dev5 $dev1 
-lv_is_on_ $vg/$lv2 $dev2 $dev5 $dev4 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-#COMM "3 out of 3 LVs are moved: from pv2 to pv5"
-prepare_lvs_ 
-pvmove -i1 $dev2 $dev5 
-lv_is_on_ $vg/$lv1 $dev1 $dev5 $dev3 $dev1 
-lv_is_on_ $vg/$lv2 $dev5 $dev3 $dev4 
-lv_is_on_ $vg/$lv3 $dev5 
-check_and_cleanup_lvs_
-
-# ---
-# areas of striping
-
-#COMM "move the 1st stripe: from pv2 of lv2 to pv1"
-prepare_lvs_ 
-pvmove -i1 -n $vg/$lv2 $dev2 $dev1 
-lv_not_changed_ $vg/$lv1 
-lv_is_on_ $vg/$lv2 $dev1 $dev3 $dev4 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-#COMM "move the 2nd stripe: from pv3 of lv2 to pv1"
-prepare_lvs_ 
-pvmove -i1 -n $vg/$lv2 $dev3 $dev1 
-lv_not_changed_ $vg/$lv1 
-lv_is_on_ $vg/$lv2 $dev2 $dev1 $dev4 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-#COMM "move the 3rd stripe: from pv4 of lv2 to pv1"
-prepare_lvs_ 
-pvmove -i1 -n $vg/$lv2 $dev4 $dev1 
-lv_not_changed_ $vg/$lv1 
-lv_is_on_ $vg/$lv2 $dev2 $dev3 $dev1 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-# ---
-# partial segment match (source segment splitted)
-
-#COMM "match to the start of segment:from pv2:0-0 to pv5"
-prepare_lvs_ 
-pvmove -i1 $dev2:0-0 $dev5 
-lv_not_changed_ $vg/$lv1 
-lv_is_on_ $vg/$lv2 $dev5 $dev2 $dev3 $dev4 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-#COMM "match to the middle of segment: from pv2:1-1 to pv5"
-prepare_lvs_ 
-pvmove -i1 $dev2:1-1 $dev5 
-lv_not_changed_ $vg/$lv1 
-lv_is_on_ $vg/$lv2 $dev2 $dev5 $dev2 $dev3 $dev4 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-#COMM "match to the end of segment: from pv2:2-2 to pv5"
-prepare_lvs_ 
-pvmove -i1 $dev2:2-2 $dev5 
-lv_not_changed_ $vg/$lv1 
-lv_is_on_ $vg/$lv2 $dev2 $dev5 $dev3 $dev4 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-# ---
-# destination segment splitted
-
-#COMM "no destination split: from pv2:0-2 to pv5"
-prepare_lvs_ 
-pvmove -i1 $dev2:0-2 $dev5 
-lv_not_changed_ $vg/$lv1 
-lv_is_on_ $vg/$lv2 $dev5 $dev3 $dev4 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-#COMM "destination split into 2: from pv2:0-2 to pv5:5-5 and pv4:5-6"
-prepare_lvs_ 
-pvmove -i1 --alloc anywhere $dev2:0-2 $dev5:5-5 $dev4:5-6 
-lv_not_changed_ $vg/$lv1 
-lv_is_on_ $vg/$lv2 $dev5 $dev4 $dev3 $dev4 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-#COMM "destination split into 3: from pv2:0-2 to {pv3,4,5}:5-5"
-prepare_lvs_ 
-pvmove -i1 --alloc anywhere $dev2:0-2 $dev3:5-5 $dev4:5-5 $dev5:5-5 
-lv_not_changed_ $vg/$lv1 
-lv_is_on_ $vg/$lv2 $dev3 $dev4 $dev5 $dev3 $dev4 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-# ---
-# alloc policy (anywhere, contiguous) with both success and failure cases
-
-#COMM "alloc normal on same PV for source and destination: from pv3:0-2 to pv3:5-7" 
-prepare_lvs_ 
-not pvmove -i1 $dev3:0-2 $dev3:5-7
-# "(cleanup previous test)"
-lv_not_changed_ $vg/$lv1 
-lv_not_changed_ $vg/$lv2 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-#COMM "alloc anywhere on same PV for source and destination: from pv3:0-2 to pv3:5-7"
-prepare_lvs_ 
-pvmove -i1 --alloc anywhere $dev3:0-2 $dev3:5-7 
-lv_not_changed_ $vg/$lv1 
-lv_is_on_ $vg/$lv2 $dev2 $dev3 $dev4 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-#COMM "alloc anywhere but better area available: from pv3:0-2 to pv3:5-7 or pv5:5-6,pv4:5-5"
-prepare_lvs_ 
-pvmove -i1 --alloc anywhere $dev3:0-2 $dev3:5-7 $dev5:5-6 $dev4:5-5 
-lv_not_changed_ $vg/$lv1 
-#lv_is_on_ $vg/$lv2 $dev2 $dev5 $dev4 $dev4 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-#COMM "alloc contiguous but area not available: from pv2:0-2 to pv5:5-5 and pv4:5-6"
-prepare_lvs_ 
-not pvmove -i1 --alloc contiguous $dev2:0-2 $dev5:5-5 $dev4:5-6
-# "(cleanup previous test)"
-lv_not_changed_ $vg/$lv1 
-lv_not_changed_ $vg/$lv2 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-#COMM "alloc contiguous and contiguous area available: from pv2:0-2 to pv5:0-0,pv5:3-5 and pv4:5-6"
-prepare_lvs_ 
-pvmove -i1 --alloc contiguous $dev2:0-2 $dev5:0-0 $dev5:3-5 $dev4:5-6 
-lv_not_changed_ $vg/$lv1 
-lv_is_on_ $vg/$lv2 $dev5 $dev3 $dev4 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-# ---
-# multiple segments in a LV
-
-#COMM "multiple source LVs: from pv3 to pv5"
-prepare_lvs_ 
-pvmove -i1 $dev3 $dev5 
-lv_is_on_ $vg/$lv1 $dev1 $dev2 $dev5 
-lv_is_on_ $vg/$lv2 $dev2 $dev5 $dev4 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-# ---
-# move inactive LV
-
-#COMM "move inactive LV: from pv2 to pv5"
-prepare_lvs_ 
-lvchange -an $vg/$lv1 
-lvchange -an $vg/$lv3 
-pvmove -i1 $dev2 $dev5 
-lv_is_on_ $vg/$lv1 $dev1 $dev5 $dev3 
-lv_is_on_ $vg/$lv2 $dev5 $dev3 $dev4 
-lv_is_on_ $vg/$lv3 $dev5 
-check_and_cleanup_lvs_
-
-# ---
-# other failure cases
-
-#COMM "no PEs to move: from pv3 to pv1"
-prepare_lvs_ 
-pvmove -i1 $dev3 $dev1 
-not pvmove -i1 $dev3 $dev1
-# "(cleanup previous test)"
-lv_is_on_ $vg/$lv1 $dev1 $dev2 $dev1 
-lv_is_on_ $vg/$lv2 $dev2 $dev1 $dev4 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-#COMM "no space available: from pv2:0-0 to pv1:0-0" 
-prepare_lvs_ 
-not pvmove -i1 $dev2:0-0 $dev1:0-0
-# "(cleanup previous test)"
-lv_not_changed_ $vg/$lv1 
-lv_not_changed_ $vg/$lv2 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-#COMM 'same source and destination: from pv1 to pv1'
-prepare_lvs_ 
-not pvmove -i1 $dev1 $dev1
-#"(cleanup previous test)"
-lv_not_changed_ $vg/$lv1 
-lv_not_changed_ $vg/$lv2 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-#COMM "sum of specified destination PEs is large enough, but it includes source PEs and the free PEs are not enough"
-prepare_lvs_ 
-not pvmove --alloc anywhere $dev1:0-2 $dev1:0-2 $dev5:0-0 2> err
-#"(cleanup previous test)"
-grep "Insufficient free space" err 
-lv_not_changed_ $vg/$lv1 
-lv_not_changed_ $vg/$lv2 
-lv_not_changed_ $vg/$lv3 
-check_and_cleanup_lvs_
-
-# ---------------------------------------------------------------------
-
-#COMM "pvmove abort"
-prepare_lvs_ 
-pvmove -i100 -b $dev1 $dev3 
-pvmove --abort 
-check_and_cleanup_lvs_
-
-#COMM "pvmove out of --metadatacopies 0 PV (bz252150)"
-vgremove -ff $vg
-pvcreate $devs
-pvcreate --metadatacopies 0 $dev1 $dev2
-vgcreate -c n $vg $devs
-lvcreate -l4 -n $lv1 $vg $dev1
-pvmove $dev1
-
-#COMM "pvmove fails activating mirror, properly restores state before pvmove"
-dmsetup create "$vg-pvmove0" --notable
-not pvmove -i 1 $dev2
-test $(dmsetup info --noheadings -c -o suspended "$vg-$lv1") = "Active"
-dmsetup remove "$vg-pvmove0"
diff --git a/test/t-pvremove-usage.sh b/test/t-pvremove-usage.sh
deleted file mode 100755 (executable)
index 5b5700f..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-aux prepare_devs 3
-pvcreate $dev1
-pvcreate --metadatacopies 0 $dev2
-pvcreate --metadatacopies 2 $dev3
-pvremove $dev2
-
-# failing, but still removing everything what can be removed
-# is somewhat odd as default, what do we have -f for?
-pvs | not grep $dev2
-pvcreate  --metadatacopies 0 $dev2
-
-# check pvremove refuses to remove pv in a vg
-vgcreate -c n $vg $dev1 $dev2
-not pvremove $dev2 $dev3
-
-for mdacp in 0 1 2; do
-    # check pvremove truly wipes the label (pvscan wont find) (---metadatacopies $mdacp)
-    pvcreate --metadatacopies $mdacp $dev3
-    pvremove $dev3
-    # try to remove agail - should fail cleanly
-    not pvremove $dev3
-    pvscan | not grep $dev3
-
-       # bz179473 refuse to wipe non-PV device without -f
-    not pvremove $dev3
-    pvremove -f $dev3
-
-    # reset setup
-    vgremove -ff $vg
-    pvcreate --metadatacopies $mdacp $dev1
-    pvcreate $dev2
-    vgcreate $vg $dev1 $dev2 
-
-    # pvremove -f fails when pv in a vg (---metadatacopies $mdacp)
-    not pvremove -f $dev1
-    pvs $dev1
-
-    # pvremove -ff fails without confirmation when pv in a vg (---metadatacopies $mdacp)
-    echo n | not pvremove -ff $dev1
-
-    # pvremove -ff succeds with confirmation when pv in a vg (---metadatacopies $mdacp)
-    pvremove -ffy $dev1
-    not pvs $dev1
-
-    vgreduce --removemissing $vg
-    pvcreate --metadatacopies $mdacp $dev1
-    vgextend $vg $dev1
-
-    # pvremove -ff -y is sufficient when pv in a vg (---metadatacopies $mdacp)" '
-    echo n | pvremove -ff -y $dev1
-
-    vgreduce --removemissing $vg
-    pvcreate --metadatacopies $mdacp $dev1
-    vgextend $vg $dev1
-done
diff --git a/test/t-read-ahead.sh b/test/t-read-ahead.sh
deleted file mode 100755 (executable)
index 6130561..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-#
-# tests basic functionality of read-ahead and ra regressions
-#
-
-test_description='Test read-ahead functionality'
-
-. ./test-utils.sh
-
-
-get_lvs_() {
-   lvs --units s --nosuffix --noheadings -o $1 "$vg"/"$lv"
-}
-
-check_lvs_() {
-   case $(get_lvs_ $1) in
-    *$2) true ;;
-    *) false ;;
-   esac
-}
-
-aux prepare_vg 5
-
-#COMM "test various read ahead settings (bz450922)"
-lvcreate -n "$lv" -l 100%FREE -i5 -I256 "$vg"
-ra="$(get_lvs_ lv_kernel_read_ahead)"
-test "$(( ( $ra / 5 ) * 5 ))" -eq $ra
-lvdisplay "$vg"/"$lv"
-not lvchange -r auto "$vg"/"$lv" 2>&1 | grep auto
-check_lvs_ lv_read_ahead auto
-check_lvs_ lv_kernel_read_ahead 5120
-lvchange -r 640 "$vg/$lv"
-check_lvs_ lv_read_ahead 640
-lvremove -ff "$vg"
-
-#COMM "read ahead is properly inherited from underlying PV"
-blockdev --setra 768 $dev1
-vgscan
-lvcreate -n $lv -L4m $vg $dev1
-test $(blockdev --getra $DM_DEV_DIR/$vg/$lv) -eq 768
-lvremove -ff $vg
-
-# Check default, active/inactive values for read_ahead / kernel_read_ahead
-lvcreate -n $lv -l 50%FREE $vg
-lvchange -an $vg/$lv
-check_lv_field_ $vg/$lv lv_read_ahead auto
-check_lv_field_ $vg/$lv lv_kernel_read_ahead -1
-lvchange -r 512 $vg/$lv
-lvchange -ay $vg/$lv
-check_lv_field_ $vg/$lv lv_read_ahead 256.00k
-check_lv_field_ $vg/$lv lv_kernel_read_ahead 256.00k
-lvremove -ff $vg
diff --git a/test/t-snapshot-autoumount-dmeventd.sh b/test/t-snapshot-autoumount-dmeventd.sh
deleted file mode 100644 (file)
index 32659af..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-# no automatic extensions please
-LVM_TEST_CONFIG_SNAPSHOT_AUTOEXTEND="
-    snapshot_autoextend_percent = 0
-    snapshot_autoextend_threshold = 100"
-
-. ./test-utils.sh
-
-which mkfs.ext2 || exit 200
-
-prepare_lvmconf
-
-aux prepare_vg 2
-aux prepare_dmeventd
-
-lvcreate -l 8 -n base $vg
-mkfs.ext2 $DM_DEV_DIR/$vg/base
-
-lvcreate -s -l 4 -n snap $vg/base
-lvchange --monitor y $vg/snap
-
-mkdir mnt
-mount $DM_DEV_DIR/$vg/snap mnt
-mount
-cat /proc/mounts | grep $vg-snap
-
-dd if=/dev/zero of=mnt/file$1 bs=1M count=17
-sync
-sleep 10 # dmeventd only checks every 10 seconds :(
-
-cat /proc/mounts | not grep $vg-snap
diff --git a/test/t-snapshot-merge.sh b/test/t-snapshot-merge.sh
deleted file mode 100755 (executable)
index 72d96da..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-set -xv
-
-which mkfs.ext3 || exit 200
-
-. ./test-utils.sh
-
-lvdev_()
-{
-    echo "$DM_DEV_DIR/$1/$2"
-}
-
-snap_lv_name_() {
-    echo ${1}_snap
-}
-
-setup_merge() {
-    local VG_NAME=$1
-    local LV_NAME=$2
-    local NUM_EXTRA_SNAPS="$3"
-    test -z "$NUM_EXTRA_SNAPS" && NUM_EXTRA_SNAPS=0
-    local BASE_SNAP_LV_NAME=$(snap_lv_name_ $LV_NAME)
-
-    lvcreate -n $LV_NAME -l 50%FREE $VG_NAME
-    lvcreate -s -n $BASE_SNAP_LV_NAME -l 20%FREE ${VG_NAME}/${LV_NAME}
-    mkfs.ext3 $(lvdev_ $VG_NAME $LV_NAME)
-
-    if [ $NUM_EXTRA_SNAPS -gt 0 ]; then
-       for i in `seq 1 $NUM_EXTRA_SNAPS`; do
-           lvcreate -s -n ${BASE_SNAP_LV_NAME}_${i} -l 20%FREE ${VG_NAME}/${LV_NAME}
-       done
-    fi
-}
-
-aux prepare_vg 1 100
-
-
-# test full merge of a single LV
-setup_merge $vg $lv1
-# now that snapshot LV is created: test if snapshot-merge target is available
-$(dmsetup targets | grep -q snapshot-merge) || exit 200
-lvs -a
-# make sure lvconvert --merge requires explicit LV listing
-not lvconvert --merge 2>err
-lvconvert --merge $vg/$(snap_lv_name_ $lv1)
-lvremove -f $vg/$lv1
-
-
-# test that an actively merging snapshot may not be removed
-setup_merge $vg $lv1
-lvconvert -i+100 --merge --background $vg/$(snap_lv_name_ $lv1)
-not lvremove -f $vg/$(snap_lv_name_ $lv1)
-lvremove -f $vg/$lv1
-
-
-# "onactivate merge" test
-setup_merge $vg $lv1
-lvs -a
-mkdir test_mnt
-mount $(lvdev_ $vg $lv1) test_mnt
-lvconvert --merge $vg/$(snap_lv_name_ $lv1)
-# -- refresh LV while FS is still mounted (merge must not start),
-#    verify 'snapshot-origin' target is still being used
-lvchange --refresh $vg/$lv1
-umount test_mnt
-rm -r test_mnt
-dmsetup table ${vg}-${lv1} | grep -q " snapshot-origin "
-# -- refresh LV to start merge (now that FS is unmounted),
-#    an active merge uses the 'snapshot-merge' target
-lvchange --refresh $vg/$lv1
-dmsetup table ${vg}-${lv1} | grep -q " snapshot-merge "
-# -- don't care if merge is still active; lvremove at this point
-#    may test stopping an active merge
-lvremove -f $vg/$lv1
-
-
-# "onactivate merge" test
-# -- deactivate/remove after disallowed merge attempt, tests
-#    to make sure preload of origin's metadata is _not_ performed
-setup_merge $vg $lv1
-lvs -a
-mkdir test_mnt
-mount $(lvdev_ $vg $lv1) test_mnt
-lvconvert --merge $vg/$(snap_lv_name_ $lv1)
-# -- refresh LV while FS is still mounted (merge must not start),
-#    verify 'snapshot-origin' target is still being used
-lvchange --refresh $vg/$lv1
-umount test_mnt
-rm -r test_mnt
-dmsetup table ${vg}-${lv1} | grep -q " snapshot-origin "
-lvremove -f $vg/$lv1
-
-
-# test multiple snapshot merge; tests copy out that is driven by merge
-setup_merge $vg $lv1 1
-lvs -a
-lvconvert --merge $vg/$(snap_lv_name_ $lv1)
-lvremove -f $vg/$lv1
-
-
-# test merging multiple snapshots that share the same tag
-setup_merge $vg $lv1
-setup_merge $vg $lv2
-lvs -a
-lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv1)
-lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv2)
-lvconvert --merge @this_is_a_test
-lvs | not grep $(snap_lv_name_ $lv1)
-lvs | not grep $(snap_lv_name_ $lv2)
-lvremove -f $vg/$lv1
-lvremove -f $vg/$lv2
-
-# FIXME following tests would need to poll merge progress, via periodic lvs?
-# Background processes don't lend themselves to lvm testsuite...
-
-# test: onactivate merge of a single lv
-
-# test: do onactivate, deactivate the origin LV, reactivate the LV, merge should resume
-
-# test: multiple onactivate merge
-
-
-vgremove -f "$vg"
diff --git a/test/t-snapshots-of-mirrors.sh b/test/t-snapshots-of-mirrors.sh
deleted file mode 100644 (file)
index fbde102..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-prepare_vg 4
-
-# Create snapshot of a mirror origin
-lvcreate -m 1 -L 10M -n lv $vg
-lvcreate -s $vg/lv -L 10M -n snap
-
-# Down-convert (mirror -> linear) under a snapshot
-lvconvert -m0 $vg/lv
-
-# Up-convert (linear -> mirror)
-lvconvert -m2 $vg/lv
-
-# Down-convert (mirror -> mirror)
-lvconvert -m1 $vg/lv
-
-# Up-convert (mirror -> mirror) -- Not supported!
-not lvconvert -m2 $vg/lv
-
-# Log conversion (disk -> core)
-lvconvert --mirrorlog core $vg/lv
-
-# Log conversion (core -> mirrored)
-lvconvert --mirrorlog mirrored $vg/lv
-
-# Log conversion (mirrored -> core)
-lvconvert --mirrorlog core $vg/lv
-
-# Log conversion (core -> disk)
-lvconvert --mirrorlog disk $vg/lv
-
-# Clean-up
-lvremove -ff $vg
diff --git a/test/t-tags.sh b/test/t-tags.sh
deleted file mode 100755 (executable)
index 906181c..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-aux prepare_pvs 5
-
-# vgcreate with --addtag
-vgcreate -c n --addtag firstvg $vg1 $dev1 $dev2
-vgcreate -c n --addtag secondvg $vg2 $dev3 $dev4
-check_vg_field_ $vg1 tags firstvg
-check_vg_field_ $vg2 tags secondvg
-vgremove -ff $vg1
-vgremove -ff $vg2
-
-# vgchange with --addtag and --deltag
-vgcreate -c n $vg1 $dev1 $dev2
-vgcreate -c n $vg2 $dev3 $dev4
-vgchange --addtag firstvgtag1 $vg1
-# adding a tag multiple times is not an error
-vgchange --addtag firstvgtag2 $vg1
-vgchange --addtag firstvgtag2 $vg1
-vgchange --addtag firstvgtag3 $vg1
-vgchange --addtag secondvgtag1 $vg2
-vgchange --addtag secondvgtag2 $vg2
-vgchange --addtag secondvgtag3 $vg2
-check_vg_field_ @firstvgtag2 tags "firstvgtag1,firstvgtag2,firstvgtag3"
-check_vg_field_ @secondvgtag1 tags "secondvgtag1,secondvgtag2,secondvgtag3"
-vgchange --deltag firstvgtag2 $vg1
-check_vg_field_ @firstvgtag1 tags "firstvgtag1,firstvgtag3"
-# deleting a tag multiple times is not an error
-vgchange --deltag firstvgtag2 $vg1
-vgchange --deltag firstvgtag1 $vg2
-vgremove -ff $vg1
-vgremove -ff $vg2
-
-# lvcreate with --addtag
-vgcreate -c n $vg1 $dev1 $dev2
-lvcreate --addtag firstlvtag1 -l 4 -n $lv1 $vg1
-lvcreate --addtag secondlvtag1 -l 4 -n $lv2 $vg1
-check_lv_field_ @firstlvtag1 tags "firstlvtag1"
-not check_lv_field_ @secondlvtag1 tags "firstlvtag1"
-check_lv_field_ $vg1/$lv2 tags "secondlvtag1"
-not check_lv_field_ $vg1/$lv1 tags "secondlvtag1"
-vgremove -ff $vg1
-
-# lvchange with --addtag and --deltag
-vgcreate -c n $vg1 $dev1 $dev2
-lvcreate -l 4 -n $lv1 $vg1
-lvcreate -l 4 -n $lv2 $vg1
-lvchange --addtag firstlvtag1 $vg1/$lv1
-# adding a tag multiple times is not an error
-lvchange --addtag firstlvtag2 $vg1/$lv1
-lvchange --addtag firstlvtag2 $vg1/$lv1
-lvchange --addtag firstlvtag3 $vg1/$lv1
-lvchange --addtag secondlvtag1 $vg1/$lv2
-lvchange --addtag secondlvtag2 $vg1/$lv2
-lvchange --addtag secondlvtag3 $vg1/$lv2
-check_lv_field_ $vg1/$lv1 tags "firstlvtag1,firstlvtag2,firstlvtag3"
-not $(check_lv_field_ $vg1/$lv1 tags "secondlvtag1")
-check_lv_field_ $vg1/$lv2 tags "secondlvtag1,secondlvtag2,secondlvtag3"
-not $(check_lv_field_ $vg1/$lv1 tags "secondlvtag1")
-# deleting a tag multiple times is not an error
-lvchange --deltag firstlvtag2 $vg1/$lv1
-lvchange --deltag firstlvtag2 $vg1/$lv1
-check_lv_field_ $vg1/$lv1 tags "firstlvtag1,firstlvtag3"
-check_lv_field_ $vg1/$lv2 tags "secondlvtag1,secondlvtag2,secondlvtag3"
diff --git a/test/t-test-partition.sh b/test/t-test-partition.sh
deleted file mode 100644 (file)
index 45a0aba..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-#
-# Testcase for bugzilla #621173 
-# excercises partition table scanning code path
-#
-
-which sfdisk || exit 200
-
-LVM_TEST_CONFIG_DEVICES="types = [\"device-mapper\", 142]"
-
-. ./test-utils.sh
-
-aux prepare_pvs 1 30
-
-pvs
-
-# create small partition table
-echo "1 2" | sfdisk $dev1
-
-pvs
diff --git a/test/t-topology-support.sh b/test/t-topology-support.sh
deleted file mode 100644 (file)
index b25ed7e..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-which mkfs.ext3 || exit 200
-
-# Get linux minor version
-linux_minor=$(echo `uname -r` | cut -d'.' -f3 | cut -d'-' -f1)
-
-test $linux_minor -ge 31 || exit 200
-
-. ./test-utils.sh
-
-check_logical_block_size()
-{
-    local DEV_=$1
-    local LOGICAL_BS=$2
-    # Verify logical_block_size - requires Linux >= 2.6.31
-    SYSFS_LOGICAL_BLOCK_SIZE=`echo /sys/block/$(basename $DEV_)/queue/logical_block_size`
-    if [ -f "$SYSFS_LOGICAL_BLOCK_SIZE" ] ; then
-       ACTUAL_LOGICAL_BLOCK_SIZE=`cat $SYSFS_LOGICAL_BLOCK_SIZE`
-       test $ACTUAL_LOGICAL_BLOCK_SIZE = $LOGICAL_BS
-    fi
-}
-
-lvdev_()
-{
-    echo "$DM_DEV_DIR/$1/$2"
-}
-
-test_snapshot_mount()
-{
-    lvcreate -L 16M -n $lv1 $vg $dev1
-    mkfs.ext3 $(lvdev_ $vg $lv1)
-    mkdir test_mnt
-    mount $(lvdev_ $vg $lv1) test_mnt
-    lvcreate -L 16M -n $lv2 -s $vg/$lv1
-    umount test_mnt
-    # mount the origin
-    mount $(lvdev_ $vg $lv1) test_mnt
-    umount test_mnt
-    # mount the snapshot
-    mount $(lvdev_ $vg $lv2) test_mnt
-    umount test_mnt
-    rm -r test_mnt
-    vgchange -an $vg
-    lvremove -f $vg/$lv2
-    lvremove -f $vg/$lv1
-}
-
-# FIXME add more topology-specific tests and validation (striped LVs, etc)
-
-NUM_DEVS=1
-PER_DEV_SIZE=34
-DEV_SIZE=$(($NUM_DEVS*$PER_DEV_SIZE))
-
-# ---------------------------------------------
-# Create "desktop-class" 4K drive
-# (logical_block_size=512, physical_block_size=4096, alignment_offset=0):
-LOGICAL_BLOCK_SIZE=512
-prepare_scsi_debug_dev $DEV_SIZE \
-    sector_size=$LOGICAL_BLOCK_SIZE physblk_exp=3
-check_logical_block_size $SCSI_DEBUG_DEV $LOGICAL_BLOCK_SIZE
-
-aux prepare_pvs $NUM_DEVS $PER_DEV_SIZE
-vgcreate -c n $vg $devs
-test_snapshot_mount
-vgremove $vg
-
-cleanup_scsi_debug_dev
-
-# ---------------------------------------------
-# Create "desktop-class" 4K drive w/ 63-sector DOS partition compensation
-# (logical_block_size=512, physical_block_size=4096, alignment_offset=3584):
-LOGICAL_BLOCK_SIZE=512
-prepare_scsi_debug_dev $DEV_SIZE \
-    sector_size=$LOGICAL_BLOCK_SIZE physblk_exp=3 lowest_aligned=7
-check_logical_block_size $SCSI_DEBUG_DEV $LOGICAL_BLOCK_SIZE
-
-aux prepare_pvs $NUM_DEVS $PER_DEV_SIZE
-vgcreate -c n $vg $devs
-test_snapshot_mount
-vgremove $vg
-
-cleanup_scsi_debug_dev
-
-# ---------------------------------------------
-# Create "enterprise-class" 4K drive
-# (logical_block_size=4096, physical_block_size=4096, alignment_offset=0):
-LOGICAL_BLOCK_SIZE=4096
-prepare_scsi_debug_dev $DEV_SIZE \
-    sector_size=$LOGICAL_BLOCK_SIZE
-check_logical_block_size $SCSI_DEBUG_DEV $LOGICAL_BLOCK_SIZE
-
-aux prepare_pvs $NUM_DEVS $PER_DEV_SIZE
-vgcreate -c n $vg $devs
-test_snapshot_mount
-vgremove $vg
diff --git a/test/t-unknown-segment.sh b/test/t-unknown-segment.sh
deleted file mode 100644 (file)
index 74a2710..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2009 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-aux prepare_vg 4
-
-lvcreate -l 1 -n $lv1 $vg
-lvcreate -l 2 -m 1 -n $lv2 $vg
-
-vgcfgbackup -f bak0 $vg
-sed -e 's,striped,unstriped,;s,mirror,unmirror,' -i.orig bak0
-vgcfgrestore -f bak0 $vg
-
-# we have on-disk metadata with unknown segments now
-not lvchange -a y $vg/$lv1 # check that activation is refused
-
-vgcfgbackup -f bak1 $vg
-cat bak1
-sed -e 's,unstriped,striped,;s,unmirror,mirror,' -i.orig bak1
-vgcfgrestore -f bak1 $vg
-vgcfgbackup -f bak2 $vg
-
-egrep -v 'description|seqno|creation_time|Generated' < bak0.orig > a
-egrep -v 'description|seqno|creation_time|Generated' < bak2 > b
-diff -u a b
diff --git a/test/t-unlost-pv.sh b/test/t-unlost-pv.sh
deleted file mode 100644 (file)
index 7a120fb..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-aux prepare_vg 3
-
-lvcreate -m 1 -l 1 -n mirror $vg
-lvchange -a n $vg/mirror
-
-check() {
-vgscan 2>&1 | tee vgscan.out
-grep "Inconsistent metadata found for VG $vg" vgscan.out
-vgscan 2>&1 | tee vgscan.out
-not grep "Inconsistent metadata found for VG $vg" vgscan.out
-}
-
-# try orphaning a missing PV (bz45867)
-disable_dev $dev1
-vgreduce --removemissing --force $vg
-enable_dev $dev1
-check
-
-# try to just change metadata; we expect the new version (with MISSING_PV set
-# on the reappeared volume) to be written out to the previously missing PV
-vgextend $vg $dev1
-disable_dev $dev1
-lvremove $vg/mirror
-enable_dev $dev1
-check
diff --git a/test/t-vgcfgbackup-usage.sh b/test/t-vgcfgbackup-usage.sh
deleted file mode 100644 (file)
index 72b37bb..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-aux prepare_pvs 4
-
-# vgcfgbackup handles similar VG names (bz458941)
-vg1=${PREFIX}vg00
-vg2=${PREFIX}vg01
-vgcreate $vg1 $dev1
-vgcreate $vg2 $dev2
-vgcfgbackup -f $TESTDIR/bak-%s >out
-grep "Volume group \"$vg1\" successfully backed up." out
-grep "Volume group \"$vg2\" successfully backed up." out
-vgremove -ff $vg1
-vgremove -ff $vg2
-
-# vgcfgbackup correctly stores metadata with missing PVs
-# and vgcfgrestore able to restore them when device reappears
-pv1_uuid=$(pvs --noheadings -o pv_uuid $dev1)
-pv2_uuid=$(pvs --noheadings -o pv_uuid $dev2)
-vgcreate $vg $devs
-lvcreate -l1 -n $lv1 $vg $dev1
-lvcreate -l1 -n $lv2 $vg $dev2
-lvcreate -l1 -n $lv3 $vg $dev3
-vgchange -a n $vg
-pvcreate -ff -y $dev1
-pvcreate -ff -y $dev2
-vgcfgbackup -f "$(pwd)/backup.$$" $vg
-sed 's/flags = \[\"MISSING\"\]/flags = \[\]/' "$(pwd)/backup.$$" > "$(pwd)/backup.$$1"
-pvcreate -ff -y --norestorefile -u $pv1_uuid $dev1
-pvcreate -ff -y --norestorefile -u $pv2_uuid $dev2
-vgcfgrestore -f "$(pwd)/backup.$$1" $vg
-vgremove -ff $vg
-
-# vgcfgbackup correctly stores metadata LVM1 with missing PVs
-# FIXME: clvmd seems to have problem with metadata format change here
-# fix it and remove this vgscan
-vgscan
-pvcreate -M1 $devs
-vgcreate -M1 -c n $vg $devs
-lvcreate -l1 -n $lv1 $vg $dev1
-pvremove -ff -y $dev2
-not lvcreate -l1 -n $lv1 $vg $dev3
-vgcfgbackup -f "$(pwd)/backup.$$" $vg
diff --git a/test/t-vgchange-maxlv.sh b/test/t-vgchange-maxlv.sh
deleted file mode 100644 (file)
index 0148315..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-prepare_dmeventd
-aux prepare_pvs 3
-
-vgcreate -c n -l 2 $vg $dev1 $dev2 $dev3
-lvcreate -n one -l 1 $vg
-lvcreate -n two -l 1 $vg
-not lvcreate -n three -l 1 $vg
-vgchange -an $vg
-vgremove -ff $vg
-
-vgcreate -c n -l 3 $vg $dev1 $dev2 $dev3
-lvcreate -n one -l 1 $vg
-lvcreate -n snap -s -l 1 $vg/one
-lvcreate -n two -l 1 $vg
-not lvcreate -n three -l 1 $vg
-vgchange --monitor y $vg
-vgchange -an $vg 2>&1 | tee vgchange.out
-not grep "event server" vgchange.out
diff --git a/test/t-vgchange-usage.sh b/test/t-vgchange-usage.sh
deleted file mode 100644 (file)
index 4baaab3..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-test_description='Exercise some vgchange diagnostics'
-
-. ./test-utils.sh
-
-aux prepare_pvs 3
-pvcreate --metadatacopies 0 $dev1
-vgcreate $vg $devs
-
-vgdisplay $vg
-
-# vgchange -p MaxPhysicalVolumes (bz202232)
-aux check_vg_field_ $vg max_pv 0
-vgchange -p 128 $vg
-aux check_vg_field_ $vg max_pv 128
-
-pv_count=$(get_vg_field $vg pv_count)
-not vgchange -p 2 $vg 2>err
-grep "MaxPhysicalVolumes is less than the current number $pv_count of PVs for" err
-aux check_vg_field_ $vg max_pv 128
-
-# vgchange -l MaxLogicalVolumes
-aux check_vg_field_ $vg max_lv 0
-vgchange -l 128 $vg
-aux check_vg_field_ $vg max_lv 128
-
-lvcreate -l4 -n$lv1 $vg
-lvcreate -l4 -n$lv2 $vg
-
-lv_count=$(get_vg_field $vg lv_count)
-not vgchange -l 1 $vg 2>err
-grep "MaxLogicalVolume is less than the current number $lv_count of LVs for"  err
-aux check_vg_field_ $vg max_lv 128
-
diff --git a/test/t-vgcreate-usage.sh b/test/t-vgcreate-usage.sh
deleted file mode 100755 (executable)
index 9f1cd82..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-test_description='Exercise some vgcreate diagnostics'
-
-. ./test-utils.sh
-
-aux prepare_devs 3
-pvcreate $dev1 $dev2
-pvcreate --metadatacopies 0 $dev3
-
-vg=${PREFIX}vg
-
-#COMM 'vgcreate accepts 8.00m physicalextentsize for VG'
-vgcreate -c n $vg --physicalextentsize 8.00m $dev1 $dev2
-check_vg_field_ $vg vg_extent_size 8.00m
-vgremove $vg
-# try vgck and to remove it again - should fail (but not segfault)
-not vgremove $vg
-not vgck $vg
-
-#COMM 'vgcreate accepts smaller (128) maxlogicalvolumes for VG'
-vgcreate -c n $vg --maxlogicalvolumes 128 $dev1 $dev2 
-check_vg_field_ $vg max_lv 128 
-vgremove $vg
-
-#COMM 'vgcreate accepts smaller (128) maxphysicalvolumes for VG'
-vgcreate -c n $vg --maxphysicalvolumes 128 $dev1 $dev2
-check_vg_field_ $vg max_pv 128
-vgremove $vg
-
-#COMM 'vgcreate rejects a zero physical extent size'
-not vgcreate -c n --physicalextentsize 0 $vg $dev1 $dev2 2>err
-grep "^  Physical extent size may not be zero\$" err
-
-#COMM 'vgcreate rejects "inherit" allocation policy'
-not vgcreate -c n --alloc inherit $vg $dev1 $dev2 2>err
-grep "^  Volume Group allocation policy cannot inherit from anything\$" err
-
-#COMM 'vgcreate rejects vgname "."'
-vginvalid=.; 
-not vgcreate -c n $vginvalid $dev1 $dev2 2>err
-grep "New volume group name \"$vginvalid\" is invalid\$" err
-
-#COMM 'vgcreate rejects vgname greater than 128 characters'
-vginvalid=thisnameisridiculouslylongtotestvalidationcodecheckingmaximumsizethisiswhathappenswhenprogrammersgetboredandorarenotcreativedonttrythisathome
-not vgcreate -c n $vginvalid $dev1 $dev2 2>err
-grep "New volume group name \"$vginvalid\" is invalid\$" err
-
-#COMM 'vgcreate rejects already existing vgname "/tmp/$vg"'
-#touch /tmp/$vg
-#not vgcreate $vg $dev1 $dev2 2>err
-#grep "New volume group name \"$vg\" is invalid\$" err
-
-#COMM "vgcreate rejects repeated invocation (run 2 times) (bz178216)"
-vgcreate -c n $vg $dev1 $dev2
-not vgcreate -c n $vg $dev1 $dev2
-vgremove -ff $vg
-
-#COMM 'vgcreate rejects MaxLogicalVolumes > 255'
-not vgcreate -c n --metadatatype 1 --maxlogicalvolumes 1024 $vg $dev1 $dev2 2>err
-grep "^  Number of volumes may not exceed 255\$" err
-
-#COMM "vgcreate fails when the only pv has --metadatacopies 0"
-not vgcreate -c n $vg $dev3
-
-# Test default (4MB) vg_extent_size as well as limits of extent_size
-not vgcreate -c n --physicalextentsize 0k $vg $dev1 $dev2
-vgcreate -c n --physicalextentsize 1k $vg $dev1 $dev2
-check_vg_field_ $vg vg_extent_size 1.00k
-vgremove -ff $vg
-not vgcreate -c n --physicalextentsize 3K $vg $dev1 $dev2
-not vgcreate -c n --physicalextentsize 1024t $vg $dev1 $dev2
-#not vgcreate --physicalextentsize 1T $vg $dev1 $dev2
-# FIXME: vgcreate allows physicalextentsize larger than pv size!
-
-# Test default max_lv, max_pv, extent_size, alloc_policy, clustered
-vgcreate -c n $vg $dev1 $dev2
-check_vg_field_ $vg vg_extent_size 4.00m
-check_vg_field_ $vg max_lv 0
-check_vg_field_ $vg max_pv 0
-check_vg_field_ $vg vg_attr "wz--n-"
-vgremove -ff $vg
-
-# Implicit pvcreate tests, test pvcreate options on vgcreate
-# --force, --yes, --metadata{size|copies|type}, --zero
-# --dataalignment[offset]
-pvremove $dev1 $dev2
-vgcreate -c n --force --yes --zero y $vg $dev1 $dev2
-vgremove -f $vg
-pvremove -f $dev1
-
-for i in 0 1 2 3
-do
-# vgcreate (lvm2) succeeds writing LVM label at sector $i
-    vgcreate -c n --labelsector $i $vg $dev1
-    dd if=$dev1 bs=512 skip=$i count=1 2>/dev/null | strings | grep -q LABELONE;
-    vgremove -f $vg
-    pvremove -f $dev1
-done
-
-# pvmetadatacopies
-for i in 1 2
-do
-    vgcreate -c n --pvmetadatacopies $i $vg $dev1
-    check_pv_field_ $dev1 pv_mda_count $i
-    vgremove -f $vg
-    pvremove -f $dev1
-done
-not vgcreate -c n --pvmetadatacopies 0 $vg $dev1
-pvcreate --metadatacopies 1 $dev2
-vgcreate -c n --pvmetadatacopies 0 $vg $dev1 $dev2
-check_pv_field_ $dev1 pv_mda_count 0
-check_pv_field_ $dev2 pv_mda_count 1
-vgremove -f $vg
-pvremove -f $dev1
-
-# metadatasize, dataalignment, dataalignmentoffset
-#COMM 'pvcreate sets data offset next to mda area'
-vgcreate -c n --metadatasize 100k --dataalignment 100k $vg $dev1
-check_pv_field_ $dev1 pe_start 200.00k
-vgremove -f $vg
-pvremove -f $dev1
-
-# data area is aligned to 1M by default,
-# data area start is shifted by the specified alignment_offset
-pv_align="1052160B" # 1048576 + (7*512)
-vgcreate -c n --metadatasize 128k --dataalignmentoffset 7s $vg $dev1
-check_pv_field_ $dev1 pe_start $pv_align "--units b"
-vgremove -f $vg
-pvremove -f $dev1
-
-# metadatatype
-for i in 1 2
-do
-    vgcreate -c n -M $i $vg $dev1
-    check_vg_field_ $vg vg_fmt lvm$i
-    vgremove -f $vg
-    pvremove -f $dev1
-done
-
-# vgcreate fails if pv belongs to existing vg
-vgcreate -c n $vg1 $dev1 $dev2
-not vgcreate $vg2 $dev2
-vgremove -f $vg1
-pvremove -f $dev1 $dev2
-
-# all PVs exist in the VG after created
-pvcreate $dev1
-vgcreate -c n $vg1 $dev1 $dev2 $dev3
-check_pv_field_ $dev1 vg_name $vg1
-check_pv_field_ $dev2 vg_name $vg1
-check_pv_field_ $dev3 vg_name $vg1
-vgremove -f $vg1
-pvremove -f $dev1 $dev2 $dev3
diff --git a/test/t-vgextend-restoremissing.sh b/test/t-vgextend-restoremissing.sh
deleted file mode 100644 (file)
index 87ff954..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-
-aux prepare_vg 3
-lvcreate -m 1 -l 1 -n mirror $vg
-lvchange -a n $vg/mirror
-lvcreate -l 1 -n lv1 $vg $dev1
-
-# try to just change metadata; we expect the new version (with MISSING_PV set
-# on the reappeared volume) to be written out to the previously missing PV
-disable_dev $dev1
-lvremove $vg/mirror
-enable_dev $dev1
-not vgck $vg 2>&1 | tee log
-grep "missing 1 physical volume" log
-not lvcreate -m 1 -l 1 -n mirror $vg # write operations fail
-vgextend --restore $vg $dev1 # restore the missing device
-vgck $vg
-lvcreate -m 1 -l 1 -n mirror $vg
diff --git a/test/t-vgextend-usage.sh b/test/t-vgextend-usage.sh
deleted file mode 100644 (file)
index eda8904..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-#
-# Exercise various vgextend commands
-#
-
-. ./test-utils.sh
-
-aux prepare_devs 5
-
-for mdatype in 1 2
-do
-
-# Explicit pvcreate
-pvcreate -M$mdatype $dev1 $dev2 $dev3 $dev4 $dev5
-vgcreate -M$mdatype $vg1 $dev1 $dev2
-vgextend $vg1 $dev3 $dev4 $dev5
-vgremove -ff $vg1
-
-# Implicit pvcreate
-pvremove $dev1 $dev2 $dev3 $dev4 $dev5
-vgcreate -M$mdatype $vg1 $dev1 $dev2
-vgextend -M$mdatype $vg1 $dev3 $dev4 $dev5
-vgremove -ff $vg1
-pvremove $dev1 $dev2 $dev3 $dev4 $dev5
-
-done
-
-# Implicit pvcreate tests, test pvcreate options on vgcreate
-# --force, --yes, --metadata{size|copies|type}, --zero
-# --dataalignment[offset]
-vgcreate $vg $dev2
-vgextend --force --yes --zero y $vg $dev1
-vgreduce $vg $dev1
-pvremove -f $dev1
-
-for i in 0 1 2 3
-do
-# vgcreate (lvm2) succeeds writing LVM label at sector $i
-    vgextend --labelsector $i $vg $dev1
-    dd if=$dev1 bs=512 skip=$i count=1 2>/dev/null | strings | grep -q LABELONE;
-    vgreduce $vg $dev1
-    pvremove -f $dev1
-done
-
-# pvmetadatacopies
-for i in 0 1 2
-do
-    vgextend --pvmetadatacopies $i $vg $dev1
-    check_pv_field_ $dev1 pv_mda_count $i
-    vgreduce $vg $dev1
-    pvremove -f $dev1
-done
-
-# metadatasize, dataalignment, dataalignmentoffset
-#COMM 'pvcreate sets data offset next to mda area'
-vgextend --metadatasize 100k --dataalignment 100k $vg $dev1
-check_pv_field_ $dev1 pe_start 200.00k
-vgreduce $vg $dev1
-pvremove -f $dev1
-
-# data area is aligned to 1M by default,
-# data area start is shifted by the specified alignment_offset
-pv_align="1052160B" # 1048576 + (7*512)
-vgextend --metadatasize 128k --dataalignmentoffset 7s $vg $dev1
-check_pv_field_ $dev1 pe_start $pv_align "--units b"
-vgremove -f $vg
-pvremove -f $dev1
-
-# vgextend fails if pv belongs to existing vg
-vgcreate $vg1 $dev1 $dev3
-vgcreate $vg2 $dev2
-not vgextend $vg2 $dev3
-vgremove -f $vg1
-vgremove -f $vg2
-pvremove -f $dev1 $dev2 $dev3
-
-#vgextend fails if vg is not resizeable
-vgcreate $vg1 $dev1 $dev2
-vgchange --resizeable n $vg1
-not vgextend $vg1 $dev3
-vgremove -f $vg1
-pvremove -f $dev1 $dev2
-
-# all PVs exist in the VG after extended
-pvcreate $dev1
-vgcreate $vg1 $dev2
-vgextend $vg1 $dev1 $dev3
-check_pv_field_ $dev1 vg_name $vg1
-check_pv_field_ $dev2 vg_name $vg1
-check_pv_field_ $dev3 vg_name $vg1
-vgremove -f $vg1
-pvremove -f $dev1 $dev2 $dev3
-
-echo test vgextend --metadataignore
-for mdacp in 1 2; do
-for ignore in y n; do
-       echo vgextend --metadataignore has proper mda_count and mda_used_count
-       vgcreate $vg $dev3
-       vgextend --metadataignore $ignore --pvmetadatacopies $mdacp $vg $dev1 $dev2
-       check_pv_field_ $dev1 pv_mda_count $mdacp
-       check_pv_field_ $dev2 pv_mda_count $mdacp
-       if [ $ignore = y ]; then
-               check_pv_field_ $dev1 pv_mda_used_count 0
-               check_pv_field_ $dev2 pv_mda_used_count 0
-       else
-               check_pv_field_ $dev1 pv_mda_used_count $mdacp
-               check_pv_field_ $dev2 pv_mda_used_count $mdacp
-       fi
-       echo vg has proper vg_mda_count and vg_mda_used_count
-       check_vg_field_ $vg vg_mda_count $(($mdacp * 2 + 1))
-       if [ $ignore = y ]; then
-               check_vg_field_ $vg vg_mda_used_count 1
-       else
-               check_vg_field_ $vg vg_mda_used_count $(($mdacp * 2 + 1))
-       fi
-       check_vg_field_ $vg vg_mda_copies unmanaged
-       vgremove $vg
-       pvremove -ff $dev1 $dev2 $dev3
-done
-done
diff --git a/test/t-vgmerge-operation.sh b/test/t-vgmerge-operation.sh
deleted file mode 100755 (executable)
index 3c7121b..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2007-2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-test_description='Test vgmerge operation'
-
-. ./test-utils.sh
-
-aux prepare_pvs 4 64
-
-# 'vgmerge succeeds with single linear LV in source VG'
-vgcreate -c n $vg1 $dev1 $dev2 
-vgcreate -c n $vg2 $dev3 $dev4 
-lvcreate -l 4 -n $lv1 $vg1 $dev1 
-vgchange -an $vg1 
-vg_validate_pvlv_counts_ $vg1 2 1 0 
-vg_validate_pvlv_counts_ $vg2 2 0 0 
-vgmerge $vg2 $vg1 
-vg_validate_pvlv_counts_ $vg2 4 1 0 
-vgremove -f $vg2
-
-# 'vgmerge succeeds with single linear LV in source and destination VG'
-vgcreate -c n $vg1 $dev1 $dev2 
-vgcreate -c n $vg2 $dev3 $dev4 
-lvcreate -l 4 -n $lv1 $vg1 
-lvcreate -l 4 -n $lv2 $vg2 
-vgchange -an $vg1 
-vgchange -an $vg2 
-vg_validate_pvlv_counts_ $vg1 2 1 0 
-vg_validate_pvlv_counts_ $vg2 2 1 0 
-vgmerge $vg2 $vg1 
-vg_validate_pvlv_counts_ $vg2 4 2 0 
-vgremove -f $vg2
-
-# 'vgmerge succeeds with linear LV + snapshots in source VG'
-vgcreate -c n $vg1 $dev1 $dev2 
-vgcreate -c n $vg2 $dev3 $dev4 
-lvcreate -l 16 -n $lv1 $vg1 
-lvcreate -l 4 -s -n $lv2 $vg1/$lv1 
-vgchange -an $vg1 
-vg_validate_pvlv_counts_ $vg1 2 2 1 
-vg_validate_pvlv_counts_ $vg2 2 0 0 
-vgmerge $vg2 $vg1 
-vg_validate_pvlv_counts_ $vg2 4 2 1 
-lvremove -f $vg2/$lv2 
-vgremove -f $vg2
-
-# 'vgmerge succeeds with mirrored LV in source VG'
-vgcreate -c n $vg1 $dev1 $dev2 $dev3 
-vgcreate -c n $vg2 $dev4 
-lvcreate -l 4 -n $lv1 -m1 $vg1 
-vgchange -an $vg1 
-vg_validate_pvlv_counts_ $vg1 3 1 0 
-vg_validate_pvlv_counts_ $vg2 1 0 0 
-vgmerge $vg2 $vg1 
-vg_validate_pvlv_counts_ $vg2 4 1 0 
-lvremove -f $vg2/$lv1 
-vgremove -f $vg2
-
-# 'vgmerge rejects LV name collision'
-vgcreate -c n $vg1 $dev1 $dev2
-vgcreate -c n $vg2 $dev3 $dev4
-lvcreate -l 4 -n $lv1 $vg1
-lvcreate -l 4 -n $lv1 $vg2
-vgchange -an $vg1
-aux vg_validate_pvlv_counts_ $vg1 2 1 0
-aux vg_validate_pvlv_counts_ $vg2 2 1 0
-not vgmerge $vg2 $vg1 2>err
-grep "Duplicate logical volume name \"$lv1\" in \"$vg2\" and \"$vg1" err
-aux vg_validate_pvlv_counts_ $vg1 2 1 0
-aux vg_validate_pvlv_counts_ $vg2 2 1 0
-vgremove -f $vg1
-vgremove -f $vg2
-
diff --git a/test/t-vgmerge-usage.sh b/test/t-vgmerge-usage.sh
deleted file mode 100755 (executable)
index 4be9e1e..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-# 'Test vgmerge command options for validity'
-
-. ./test-utils.sh
-
-aux prepare_pvs 4
-
-# 'vgmerge normal operation'
-# ensure ordering does not matter
-vgcreate  $vg1 $dev1 $dev2 
-vgcreate  $vg2 $dev3 $dev4 
-vgmerge $vg1 $vg2 
-vgremove $vg1
-vgcreate -c n $vg2 $dev1 $dev2
-vgcreate -c n $vg1 $dev3 $dev4
-vgmerge $vg2 $vg1
-vgremove $vg2
-
-# 'vgmerge rejects duplicate vg name'
-vgcreate  $vg1 $dev1 $dev2 
-vgcreate  $vg2 $dev3 $dev4 
-not vgmerge $vg1 $vg1 2>err
-grep "^  Duplicate volume group name \"$vg1\"\$" err 
-vgremove $vg2 
-vgremove $vg1
-
-# 'vgmerge rejects vgs with incompatible extent_size'
-vgcreate  --physicalextentsize 4M $vg1 $dev1 $dev2 
-vgcreate  --physicalextentsize 8M $vg2 $dev3 $dev4 
-not vgmerge $vg1 $vg2 2>err
-grep "^  Extent sizes differ" err 
-vgremove $vg2 
-vgremove $vg1
-
-# 'vgmerge rejects vgmerge because max_pv is exceeded'
-vgcreate  --maxphysicalvolumes 2 $vg1 $dev1 $dev2 
-vgcreate  --maxphysicalvolumes 2 $vg2 $dev3 $dev4 
-not vgmerge $vg1 $vg2 2>err
-grep "^  Maximum number of physical volumes (2) exceeded" err 
-vgremove $vg2 
-vgremove $vg1
-
-# 'vgmerge rejects vg with active lv'
-vgcreate $vg1 $dev1 $dev2 
-vgcreate $vg2 $dev3 $dev4 
-lvcreate -l 4 -n lv1 $vg2 
-not vgmerge $vg1 $vg2 2>err
-grep "^  Logical volumes in \"$vg2\" must be inactive\$" err 
-vgremove -f $vg2 
-vgremove -f $vg1
-
-# 'vgmerge rejects vgmerge because max_lv is exceeded' 
-vgcreate --maxlogicalvolumes 2 $vg1 $dev1 $dev2 
-vgcreate --maxlogicalvolumes 2 $vg2 $dev3 $dev4 
-lvcreate -l 4 -n lv1 $vg1 
-lvcreate -l 4 -n lv2 $vg1 
-lvcreate -l 4 -n lv3 $vg2 
-vgchange -an $vg1 
-vgchange -an $vg2 
-not vgmerge $vg1 $vg2 2>err
-grep "^  Maximum number of logical volumes (2) exceeded" err 
-vgremove -f $vg2 
-vgremove -f $vg1
diff --git a/test/t-vgreduce-usage.sh b/test/t-vgreduce-usage.sh
deleted file mode 100755 (executable)
index 6a09cfa..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-aux prepare_devs 4
-
-for mdatype in 1 2
-do
-    # setup PVs
-    pvcreate -M$mdatype $dev1 $dev2 
-
-    # (lvm$mdatype) vgreduce removes only the specified pv from vg (bz427382)" '
-    vgcreate -c n -M$mdatype $vg1 $dev1 $dev2
-    vgreduce $vg1 $dev1
-    check_pv_field_ $dev2 vg_name $vg1
-    vgremove -f $vg1
-
-    # (lvm$mdatype) vgreduce rejects removing the last pv (--all)
-    vgcreate -c n -M$mdatype $vg1 $dev1 $dev2
-    not vgreduce --all $vg1
-    vgremove -f $vg1
-
-    # (lvm$mdatype) vgreduce rejects removing the last pv
-    vgcreate -c n -M$mdatype $vg1 $dev1 $dev2
-    not vgreduce $vg1 $dev1 $dev2
-    vgremove -f $vg1
-
-    pvremove -ff $dev1 $dev2
-done
-
-mdatype=2 # we only expect the following to work for lvm2 metadata
-
-# (lvm$mdatype) setup PVs (--metadatacopies 0)
-pvcreate -M$mdatype $dev1 $dev2
-pvcreate --metadatacopies 0 -M$mdatype $dev3 $dev4
-
-# (lvm$mdatype) vgreduce rejects removing pv with the last mda copy (bz247448)
-vgcreate -c n -M$mdatype $vg1 $dev1 $dev3
-not vgreduce $vg1 $dev1
-vgremove -f $vg1
-
-#COMM "(lvm$mdatype) vgreduce --removemissing --force repares to linear (bz221921)"
-# (lvm$mdatype) setup: create mirror & damage one pv
-vgcreate -c n -M$mdatype $vg1 $dev1 $dev2 $dev3
-lvcreate -n $lv1 -m1 -l 4 $vg1
-lvcreate -n $lv2  -l 4 $vg1 $dev2
-lvcreate -n $lv3 -l 4 $vg1 $dev3
-vgchange -an $vg1
-aux disable_dev $dev1
-# (lvm$mdatype) vgreduce --removemissing --force repares to linear
-vgreduce --removemissing --force $vg1
-check_lv_field_ $vg1/$lv1 segtype linear
-vg_validate_pvlv_counts_ $vg1 2 3 0
-# cleanup
-aux enable_dev $dev1
-vgremove -ff $vg1
-
-#COMM "vgreduce rejects --removemissing --mirrorsonly --force when nonmirror lv lost too"
-# (lvm$mdatype) setup: create mirror + linear lvs
-vgcreate -c n -M$mdatype $vg1 $devs
-lvcreate -n $lv2 -l 4 $vg1
-lvcreate -m1 -n $lv1 -l 4 $vg1 $dev1 $dev2 $dev3
-lvcreate -n $lv3 -l 4 $vg1 $dev3
-pvs --segments -o +lv_name # for record only
-# (lvm$mdatype) setup: damage one pv
-vgchange -an $vg1 
-aux disable_dev $dev1
-#pvcreate -ff -y $dev1
-# vgreduce rejects --removemissing --mirrorsonly --force when nonmirror lv lost too
-not vgreduce -c n --removemissing --mirrorsonly --force $vg1
-
-aux enable_dev $dev1
-
-pvs -P # for record
-lvs -P # for record
-vgs -P # for record
diff --git a/test/t-vgrename-usage.sh b/test/t-vgrename-usage.sh
deleted file mode 100755 (executable)
index 61e861c..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-aux prepare_devs 4
-pvcreate $dev1 $dev2
-pvcreate --metadatacopies 0 $dev3 $dev4
-
-# vgrename normal operation - rename vg1 to vg2
-# vgrename normal operation - rename vg2 to vg1
-# ensure name ordering does not matter
-vgcreate $vg1 $dev1 $dev2
-vgrename $vg1 $vg2
-check_vg_field_ $vg2 vg_name $vg2
-vgrename $vg2 $vg1
-check_vg_field_ $vg1 vg_name $vg1
-vgremove $vg1
-
-# vgrename by uuid (bz231187)
-vgcreate $vg1 $dev1 $dev3
-UUID=$(vgs --noheading -o vg_uuid $vg1)
-check_vg_field_ $vg1 vg_uuid $UUID
-vgrename $UUID $vg2
-check_vg_field_ $vg2 vg_name $vg2
-vgremove $vg2
-
-# vgrename fails - new vg already exists
-vgcreate $vg1 $dev1
-vgcreate $vg2 $dev2
-not vgrename $vg1 $vg2
-vgremove $vg1
-vgremove $vg2
-
diff --git a/test/t-vgsplit-operation.sh b/test/t-vgsplit-operation.sh
deleted file mode 100755 (executable)
index 9a46a8e..0000000
+++ /dev/null
@@ -1,290 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2007 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-# Test vgsplit operation, including different LV types
-
-. ./test-utils.sh
-
-COMM() {  
-       LAST_TEST="$@"
-}
-
-prepare_pvs 5 258
-# FIXME: paramaterize lvm1 vs lvm2 metadata; most of these tests should run
-# fine with lvm1 metadata as well; for now, just add disks 5 and 6 as lvm1
-# metadata
-
-#
-# vgsplit can be done into a new or existing VG
-#
-for i in new existing
-do
-       #
-       # We can have PVs or LVs on the cmdline
-       #
-       for j in PV LV
-       do
-COMM "vgsplit correctly splits single linear LV into $i VG ($j args)"
-               vgcreate $vg1 $dev1 $dev2 
-               if [ $i = existing ]; then
-                  vgcreate $vg2 $dev3 $dev4
-               fi 
-               lvcreate -l 4 -n $lv1 $vg1 $dev1 
-               vgchange -an $vg1 
-               if [ $j = PV ]; then
-                 vgsplit $vg1 $vg2 $dev1
-               else
-                 vgsplit -n $lv1 $vg1 $vg2
-               fi 
-               vg_validate_pvlv_counts_ $vg1 1 0 0 
-               if [ $i = existing ]; then
-                  aux vg_validate_pvlv_counts_ $vg2 3 1 0
-               else
-                  aux vg_validate_pvlv_counts_ $vg2 1 1 0
-               fi 
-               lvremove -f $vg2/$lv1 
-               vgremove -f $vg2 
-               vgremove -f $vg1
-
-COMM "vgsplit correctly splits single striped LV into $i VG ($j args)"
-               vgcreate $vg1 $dev1 $dev2 
-               if [ $i = existing ]; then
-                  vgcreate $vg2 $dev3 $dev4
-               fi 
-               lvcreate -l 4 -i 2 -n $lv1 $vg1 $dev1 $dev2 
-               vgchange -an $vg1 
-               if [ $j = PV ]; then
-                 vgsplit $vg1 $vg2 $dev1 $dev2
-               else
-                 vgsplit -n $lv1 $vg1 $vg2
-               fi 
-               if [ $i = existing ]; then
-                 aux vg_validate_pvlv_counts_ $vg2 4 1 0
-               else
-                 aux vg_validate_pvlv_counts_ $vg2 2 1 0
-               fi 
-               lvremove -f $vg2/$lv1 
-               vgremove -f $vg2
-
-COMM "vgsplit correctly splits mirror LV into $i VG ($j args)" 
-               vgcreate -c n $vg1 $dev1 $dev2 $dev3 
-               if [ $i = existing ]; then
-                 vgcreate -c n $vg2 $dev4
-               fi 
-               lvcreate -l 64 -m1 -n $lv1 $vg1 $dev1 $dev2 $dev3 
-               vgchange -an $vg1 
-               if [ $j = PV ]; then
-                 vgsplit $vg1 $vg2 $dev1 $dev2 $dev3
-               else
-                 vgsplit -n $lv1 $vg1 $vg2
-               fi 
-               if [ $i = existing ]; then
-                 aux vg_validate_pvlv_counts_ $vg2 4 1 0
-               else
-                 aux vg_validate_pvlv_counts_ $vg2 3 1 0
-               fi 
-               lvremove -f $vg2/$lv1 
-               vgremove -f $vg2
-
-COMM "vgsplit correctly splits origin and snapshot LV into $i VG ($j args)" 
-               vgcreate -c n $vg1 $dev1 $dev2 
-               if [ $i = existing ]; then
-                 vgcreate -c n $vg2 $dev3 $dev4
-               fi 
-               lvcreate -l 64 -i 2 -n $lv1 $vg1 $dev1 $dev2 
-               lvcreate -l 4 -i 2 -s -n $lv2 $vg1/$lv1 
-               vgchange -an $vg1 
-               if [ $j = PV ]; then
-                 vgsplit $vg1 $vg2 $dev1 $dev2
-               else
-                 vgsplit -n $lv1 $vg1 $vg2
-               fi 
-               if [ $i = existing ]; then
-                 aux vg_validate_pvlv_counts_ $vg2 4 2 1
-               else
-                 aux vg_validate_pvlv_counts_ $vg2 2 2 1
-               fi 
-               lvremove -f $vg2/$lv2 
-               lvremove -f $vg2/$lv1 
-               vgremove -f $vg2
-
-COMM "vgsplit correctly splits linear LV but not snap+origin LV into $i VG ($j args)" 
-               vgcreate -c n $vg1 $dev1 $dev2 
-               if [ $i = existing ]; then
-                 vgcreate -c n $vg2 $dev3
-               fi 
-               lvcreate -l 64 -i 2 -n $lv1 $vg1 
-               lvcreate -l 4 -i 2 -s -n $lv2 $vg1/$lv1 
-               vgextend $vg1 $dev4 
-               lvcreate -l 64 -n $lv3 $vg1 $dev4 
-               vgchange -an $vg1 
-               if [ $j = PV ]; then
-                 vgsplit $vg1 $vg2 $dev4
-               else
-                 vgsplit -n $lv3 $vg1 $vg2
-               fi 
-               if [ $i = existing ]; then
-                 aux vg_validate_pvlv_counts_ $vg2 2 1 0
-                 aux vg_validate_pvlv_counts_ $vg1 2 2 1
-               else
-                 aux vg_validate_pvlv_counts_ $vg2 1 1 0
-                 aux vg_validate_pvlv_counts_ $vg1 2 2 1
-               fi 
-               lvremove -f $vg1/$lv2 
-               lvremove -f $vg1/$lv1 
-               lvremove -f $vg2/$lv3 
-               vgremove -f $vg1 
-               vgremove -f $vg2
-
-COMM "vgsplit correctly splits linear LV but not mirror LV into $i VG ($j args)" 
-               vgcreate -c n $vg1 $dev1 $dev2 $dev3 
-               if [ $i = existing ]; then
-                 vgcreate -c n $vg2 $dev5
-               fi 
-               lvcreate -l 64 -m1 -n $lv1 $vg1 $dev1 $dev2 $dev3 
-               vgextend $vg1 $dev4 
-               lvcreate -l 64 -n $lv2 $vg1 $dev4 
-               vgchange -an $vg1 
-               vgs
-               lvs 
-               pvs
-               if [ $j = PV ]; then
-                 vgsplit $vg1 $vg2 $dev4
-               else
-                 vgsplit -n $lv2 $vg1 $vg2
-               fi 
-               if [ $i = existing ]; then
-                 aux vg_validate_pvlv_counts_ $vg1 3 1 0
-                 aux vg_validate_pvlv_counts_ $vg2 2 1 0
-               else
-               vgs
-               lvs 
-               pvs
-                 aux vg_validate_pvlv_counts_ $vg1 3 1 0
-                 aux vg_validate_pvlv_counts_ $vg2 1 1 0
-               fi 
-               lvremove -f $vg1/$lv1 
-               lvremove -f $vg2/$lv2 
-               vgremove -f $vg1 
-               vgremove -f $vg2
-
-       done
-done
-
-#
-# Test more complex setups where the code has to find associated PVs and
-# LVs to split the VG correctly
-# 
-COMM "vgsplit fails splitting 3 striped LVs into VG when only 1 LV specified" 
-vgcreate $vg1 $dev1 $dev2 $dev3 $dev4 
-lvcreate -l 4 -n $lv1 -i 2 $vg1 $dev1 $dev2 
-lvcreate -l 4 -n $lv2 -i 2 $vg1 $dev2 $dev3 
-lvcreate -l 4 -n $lv3 -i 2 $vg1 $dev3 $dev4 
-vgchange -an $vg1 
-not vgsplit -n $lv1 $vg1 $vg2
-vgremove -ff $vg1
-
-COMM "vgsplit fails splitting one LV with 2 snapshots, only origin LV specified" 
-vgcreate -c n $vg1 $dev1 $dev2 $dev3 $dev4 
-lvcreate -l 16 -n $lv1 $vg1 $dev1 $dev2 
-lvcreate -l 4 -n $lv2 -s $vg1/$lv1 $dev3
-lvcreate -l 4 -n $lv3 -s $vg1/$lv1 $dev4
-vg_validate_pvlv_counts_ $vg1 4 3 2 
-vgchange -an $vg1 
-not vgsplit -n $lv1 $vg1 $vg2;
-lvremove -f $vg1/$lv2 
-lvremove -f $vg1/$lv3 
-lvremove -f $vg1/$lv1 
-vgremove -ff $vg1
-
-COMM "vgsplit fails splitting one LV with 2 snapshots, only snapshot LV specified" 
-vgcreate -c n $vg1 $dev1 $dev2 $dev3 $dev4 
-lvcreate -l 16 -n $lv1 $vg1 $dev1 $dev2 
-lvcreate -l 4 -n $lv2 -s $vg1/$lv1 $dev3
-lvcreate -l 4 -n $lv3 -s $vg1/$lv1 $dev4
-vg_validate_pvlv_counts_ $vg1 4 3 2 
-vgchange -an $vg1 
-not vgsplit -n $lv2 $vg1 $vg2
-lvremove -f $vg1/$lv2 
-lvremove -f $vg1/$lv3 
-lvremove -f $vg1/$lv1 
-vgremove -ff $vg1
-
-COMM "vgsplit fails splitting one mirror LV, only one PV specified" 
-vgcreate -c n $vg1 $dev1 $dev2 $dev3 $dev4 
-lvcreate -l 16 -n $lv1 -m1 $vg1 $dev1 $dev2 $dev3 
-vg_validate_pvlv_counts_ $vg1 4 1 0 
-vgchange -an $vg1 
-not vgsplit $vg1 $vg2 $dev2 
-vgremove -ff $vg1
-
-COMM "vgsplit fails splitting 1 mirror + 1 striped LV, only striped LV specified" 
-vgcreate -c n $vg1 $dev1 $dev2 $dev3 $dev4 
-lvcreate -l 16 -n $lv1 -m1 $vg1 $dev1 $dev2 $dev3 
-lvcreate -l 16 -n $lv2 -i 2 $vg1 $dev3 $dev4 
-vg_validate_pvlv_counts_ $vg1 4 2 0 
-vgchange -an $vg1 
-not vgsplit -n $lv2 $vg1 $vg2 2>err
-vgremove -ff $vg1
-
-#
-# Verify vgsplit rejects active LVs only when active LVs involved in split
-#
-COMM "vgsplit fails, active mirror involved in split" 
-vgcreate -c n $vg1 $dev1 $dev2 $dev3 $dev4 
-lvcreate -l 16 -n $lv1 -m1 $vg1 $dev1 $dev2 $dev3 
-lvcreate -l 16 -n $lv2 $vg1 $dev4 
-lvchange -an $vg1/$lv2 
-vg_validate_pvlv_counts_ $vg1 4 2 0 
-not vgsplit -n $lv1 $vg1 $vg2;
-vg_validate_pvlv_counts_ $vg1 4 2 0 
-vgremove -ff $vg1
-
-COMM "vgsplit succeeds, active mirror not involved in split" 
-vgcreate -c n $vg1 $dev1 $dev2 $dev3 $dev4 
-lvcreate -l 16 -n $lv1 -m1 $vg1 $dev1 $dev2 $dev3 
-lvcreate -l 16 -n $lv2 $vg1 $dev4 
-lvchange -an $vg1/$lv2 
-vg_validate_pvlv_counts_ $vg1 4 2 0 
-vgsplit -n $lv2 $vg1 $vg2 
-vg_validate_pvlv_counts_ $vg1 3 1 0 
-vg_validate_pvlv_counts_ $vg2 1 1 0 
-vgremove -ff $vg1 
-vgremove -ff $vg2
-
-COMM "vgsplit fails, active snapshot involved in split" 
-vgcreate -c n $vg1 $dev1 $dev2 $dev3 $dev4 
-lvcreate -l 64 -i 2 -n $lv1 $vg1 $dev1 $dev2 
-lvcreate -l 4 -i 2 -s -n $lv2 $vg1/$lv1 
-lvcreate -l 64 -i 2 -n $lv3 $vg1 $dev3 $dev4 
-lvchange -an $vg1/$lv3 
-vg_validate_pvlv_counts_ $vg1 4 3 1 
-not vgsplit -n $lv2 $vg1 $vg2;
-vg_validate_pvlv_counts_ $vg1 4 3 1 
-lvremove -f $vg1/$lv2 
-vgremove -ff $vg1
-
-COMM "vgsplit succeeds, active snapshot not involved in split" 
-vgcreate -c n $vg1 $dev1 $dev2 $dev3 
-lvcreate -l 64 -i 2 -n $lv1 $vg1 $dev1 $dev2 
-lvcreate -l 4 -s -n $lv2 $vg1/$lv1 
-vgextend $vg1 $dev4 
-lvcreate -l 64 -n $lv3 $vg1 $dev4 
-lvchange -an $vg1/$lv3 
-vg_validate_pvlv_counts_ $vg1 4 3 1 
-vgsplit -n $lv3 $vg1 $vg2 
-vg_validate_pvlv_counts_ $vg1 3 2 1 
-vg_validate_pvlv_counts_ $vg2 1 1 0 
-vgchange -an $vg1 
-lvremove -f $vg1/$lv2 
-vgremove -ff $vg1 
-vgremove -ff $vg2
-
diff --git a/test/t-vgsplit-stacked.sh b/test/t-vgsplit-stacked.sh
deleted file mode 100644 (file)
index 424156f..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-. ./test-utils.sh
-
-prepare_lvmconf '[ "a/dev\/mirror/", "a/dev\/mapper\/.*$/", "a/dev\/LVMTEST/", "r/.*/" ]'
-aux prepare_devs 3
-
-pvcreate $devs
-vgcreate $vg1 $dev1 $dev2
-lvcreate -n $lv1 -l 100%FREE $vg1
-
-#top VG
-pvcreate $DM_DEV_DIR/$vg1/$lv1
-vgcreate $vg $DM_DEV_DIR/$vg1/$lv1 $dev3
-
-vgchange -a n $vg
-vgchange -a n $vg1
-
-# this should fail but not segfault, RHBZ 481793.
-not vgsplit $vg $vg1 $dev3
diff --git a/test/t-vgsplit-usage.sh b/test/t-vgsplit-usage.sh
deleted file mode 100755 (executable)
index ade39d8..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2007-2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-# Test vgsplit command options for validity
-
-. ./test-utils.sh
-
-aux prepare_devs 5
-
-for mdatype in 1 2
-do
-
-pvcreate -M$mdatype $devs
-
-# ensure name order does not matter
-# NOTE: if we're using lvm1, we must use -M on vgsplit
-vgcreate -M$mdatype $vg1 $devs
-vgsplit -M$mdatype $vg1 $vg2 $dev1
-vgremove $vg1
-vgremove $vg2
-vgcreate -M$mdatype $vg2 $devs
-vgsplit -M$mdatype $vg2 $vg1 $dev1
-vgremove $vg1
-vgremove $vg2
-
-# vgsplit accepts new vg as destination of split
-# lvm1 -- bz244792
-vgcreate -M$mdatype $vg1 $devs
-vgsplit $vg1 $vg2 $dev1 1>err
-grep "New volume group \"$vg2\" successfully split from \"$vg1\"" err 
-vgremove $vg1 
-vgremove $vg2
-
-# vgsplit accepts existing vg as destination of split
-vgcreate -M$mdatype $vg1 $dev1 $dev2 
-vgcreate -M$mdatype $vg2 $dev3 $dev4 
-vgsplit $vg1 $vg2 $dev1 1>err
-grep "Existing volume group \"$vg2\" successfully split from \"$vg1\"" err 
-vgremove $vg1 
-vgremove $vg2
-
-# vgsplit accepts --maxphysicalvolumes 128 on new VG
-vgcreate -M$mdatype $vg1 $dev1 $dev2 
-vgsplit --maxphysicalvolumes 128 $vg1 $vg2 $dev1 
-check_vg_field_ $vg2 max_pv 128 
-vgremove $vg1 
-vgremove $vg2
-
-# vgsplit accepts --maxlogicalvolumes 128 on new VG
-vgcreate -M$mdatype $vg1 $dev1 $dev2 
-vgsplit --maxlogicalvolumes 128 $vg1 $vg2 $dev1 
-check_vg_field_ $vg2 max_lv 128 
-vgremove $vg1 
-vgremove $vg2
-
-# vgsplit rejects split because max_pv of destination would be exceeded
-vgcreate -M$mdatype --maxphysicalvolumes 2 $vg1 $dev1 $dev2
-vgcreate -M$mdatype --maxphysicalvolumes 2 $vg2 $dev3 $dev4
-not vgsplit $vg1 $vg2 $dev1 2>err;
-grep "^  Maximum number of physical volumes (2) exceeded" err
-vgremove $vg2
-vgremove $vg1
-
-# vgsplit rejects split because maxphysicalvolumes given with existing vg
-vgcreate -M$mdatype --maxphysicalvolumes 2 $vg1 $dev1 $dev2 
-vgcreate -M$mdatype --maxphysicalvolumes 2 $vg2 $dev3 $dev4 
-not vgsplit --maxphysicalvolumes 2 $vg1 $vg2 $dev1 2>err;
-grep "^  Volume group \"$vg2\" exists, but new VG option specified" err 
-vgremove $vg2 
-vgremove $vg1
-
-# vgsplit rejects split because maxlogicalvolumes given with existing vg
-vgcreate -M$mdatype --maxlogicalvolumes 2 $vg1 $dev1 $dev2 
-vgcreate -M$mdatype --maxlogicalvolumes 2 $vg2 $dev3 $dev4 
-not vgsplit --maxlogicalvolumes 2 $vg1 $vg2 $dev1 2>err
-grep "^  Volume group \"$vg2\" exists, but new VG option specified" err 
-vgremove $vg2 
-vgremove $vg1
-
-# vgsplit rejects split because alloc given with existing vg
-vgcreate -M$mdatype --alloc cling $vg1 $dev1 $dev2 
-vgcreate -M$mdatype --alloc cling $vg2 $dev3 $dev4 
-not vgsplit --alloc cling $vg1 $vg2 $dev1 2>err;
-grep "^  Volume group \"$vg2\" exists, but new VG option specified" err 
-vgremove $vg2 
-vgremove $vg1
-
-# vgsplit rejects split because clustered given with existing vg
-vgcreate -M$mdatype --clustered n $vg1 $dev1 $dev2 
-vgcreate -M$mdatype --clustered n $vg2 $dev3 $dev4 
-not vgsplit --clustered n $vg1 $vg2 $dev1 2>err
-grep "^  Volume group \"$vg2\" exists, but new VG option specified" err 
-vgremove $vg2 
-vgremove $vg1
-
-# vgsplit rejects vg with active lv
-pvcreate -M$mdatype -ff $dev3 $dev4 
-vgcreate -M$mdatype $vg1 $dev1 $dev2 
-vgcreate -M$mdatype $vg2 $dev3 $dev4 
-lvcreate -l 4 -n $lv1 $vg1 
-not vgsplit $vg1 $vg2 $dev1 2>err;
-grep "^  Logical volumes in \"$vg1\" must be inactive\$" err 
-vgremove -f $vg2 
-vgremove -f $vg1
-
-# vgsplit rejects split because max_lv is exceeded
-vgcreate -M$mdatype --maxlogicalvolumes 2 $vg1 $dev1 $dev2 
-vgcreate -M$mdatype --maxlogicalvolumes 2 $vg2 $dev3 $dev4 
-lvcreate -l 4 -n $lv1 $vg1 
-lvcreate -l 4 -n $lv2 $vg1 
-lvcreate -l 4 -n $lv3 $vg2 
-vgchange -an $vg1 
-vgchange -an $vg2 
-not vgsplit $vg1 $vg2 $dev1 2>err;
-grep "^  Maximum number of logical volumes (2) exceeded" err 
-vgremove -f $vg2 
-vgremove -f $vg1
-
-# vgsplit verify default - max_lv attribute from new VG is same as source VG" \
-vgcreate -M$mdatype $vg1 $dev1 $dev2 
-lvcreate -l 4 -n $lv1 $vg1 
-vgchange -an $vg1 
-vgsplit $vg1 $vg2 $dev1 
-compare_vg_field_ $vg1 $vg2 max_lv 
-vgremove -f $vg2 
-vgremove -f $vg1
-
-# vgsplit verify default - max_pv attribute from new VG is same as source VG" \
-vgcreate -M$mdatype $vg1 $dev1 $dev2 
-lvcreate -l 4 -n $lv1 $vg1 
-vgchange -an $vg1 
-vgsplit $vg1 $vg2 $dev1 
-compare_vg_field_ $vg1 $vg2 max_pv 
-vgremove -f $vg2 
-vgremove -f $vg1
-
-# vgsplit verify default - vg_fmt attribute from new VG is same as source VG" \
-vgcreate -M$mdatype $vg1 $dev1 $dev2 
-lvcreate -l 4 -n $lv1 $vg1 
-vgchange -an $vg1 
-vgsplit $vg1 $vg2 $dev1 
-compare_vg_field_ $vg1 $vg2 vg_fmt 
-vgremove -f $vg2 
-vgremove -f $vg1
-
-# vgsplit rejects split because PV not in VG
-vgcreate -M$mdatype $vg1 $dev1 $dev2 
-vgcreate -M$mdatype $vg2 $dev3 $dev4 
-lvcreate -l 4 -n $lv1 $vg1 
-lvcreate -l 4 -n $lv2 $vg1 
-vgchange -an $vg1 
-not vgsplit $vg1 $vg2 $dev3 2>err;
-vgremove -f $vg2 
-vgremove -f $vg1
-done
-
-# ONLY LVM2 metadata
-# setup PVs" '
-pvcreate --metadatacopies 0 $dev5
-
-# vgsplit rejects to give away pv with the last mda copy
-vgcreate $vg1 $dev5 $dev2  
-lvcreate -l 10 -n $lv1  $vg1 
-lvchange -an $vg1/$lv1 
-vg_validate_pvlv_counts_ $vg1 2 1 0 
-not vgsplit  $vg1 $vg2 $dev5;
-vg_validate_pvlv_counts_ $vg1 2 1 0 
-vgremove -ff $vg1
-
-# vgsplit rejects split because metadata types differ
-pvcreate -ff -M1 $dev3 $dev4 
-pvcreate -ff $dev1 $dev2 
-vgcreate -M1 $vg1 $dev3 $dev4 
-vgcreate $vg2 $dev1 $dev2 
-not vgsplit $vg1 $vg2 $dev3 2>err;
-grep "^  Metadata types differ" err 
-vgremove $vg2 
-vgremove $vg1
-
diff --git a/test/test-utils.sh b/test/test-utils.sh
deleted file mode 100644 (file)
index e1aea8a..0000000
+++ /dev/null
@@ -1,457 +0,0 @@
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# 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
-
-aux() {
-        # use just "$@" for verbose operation
-       "$@" > /dev/null 2> /dev/null
-       #"$@"
-}
-
-STACKTRACE() {
-       trap - ERR;
-       i=0;
-
-       while FUNC=${FUNCNAME[$i]}; test "$FUNC" != "main"; do 
-               echo "$i ${FUNC}() called from ${BASH_SOURCE[$i]}:${BASH_LINENO[$i]}"
-               i=$(($i + 1));
-       done
-
-       # Get backtraces from coredumps
-       if which gdb >& /dev/null; then
-               echo bt full > gdb_commands.txt
-               echo l >> gdb_commands.txt
-               echo quit >> gdb_commands.txt
-               for core in `ls core* 2>/dev/null`; do
-                       bin=$(gdb -batch -c $core 2>&1 | grep "generated by" | \
-                               sed -e "s,.*generated by \`\([^ ']*\).*,\1,")
-                       gdb -batch -c $core -x gdb_commands.txt `which $bin`
-               done
-       fi
-
-       test -f debug.log && {
-               sed -e "s,^,## DEBUG: ,;s,$top_srcdir/\?,," < debug.log
-       }
-}
-
-init_udev_transaction() {
-       if test "$DM_UDEV_SYNCHRONISATION" = 1; then
-               COOKIE=$(dmsetup udevcreatecookie)
-               # Cookie is not generated if udev is not running!
-               if test -n "$COOKIE"; then
-                       export DM_UDEV_COOKIE=$COOKIE
-               fi
-       fi
-}
-
-finish_udev_transaction() {
-       if test "$DM_UDEV_SYNCHRONISATION" = 1 -a -n "$DM_UDEV_COOKIE"; then
-               dmsetup udevreleasecookie
-               unset DM_UDEV_COOKIE
-       fi
-}
-
-prepare_clvmd() {
-       if test -z "$LVM_TEST_LOCKING" || test "$LVM_TEST_LOCKING" -ne 3 ; then
-               return 0 # not needed
-       fi
-
-       if pgrep clvmd ; then
-               echo "Cannot use fake cluster locking with real clvmd ($(pgrep clvmd)) running."
-               exit 200
-       fi
-
-       # skip if we don't have our own clvmd...
-       (which clvmd | grep $abs_builddir) || exit 200
-
-       # skip if we singlenode is not compiled in
-       (clvmd --help 2>&1 | grep "Available cluster managers" | grep singlenode) || exit 200
-
-       trap_teardown
-
-       clvmd -Isinglenode -d 1 &
-       LOCAL_CLVMD="$!"
-
-       # check that it is really running now
-       sleep .1
-       ps $LOCAL_CLVMD || exit 200
-}
-
-prepare_dmeventd() {
-       if pgrep dmeventd ; then
-               echo "Cannot test dmeventd with real dmeventd ($(pgrep dmeventd)) running."
-               exit 200
-       fi
-
-       # skip if we don't have our own dmeventd...
-       (which dmeventd | grep $abs_builddir) || exit 200
-
-       trap_teardown
-
-       dmeventd -f &
-       LOCAL_DMEVENTD="$!"
-}
-
-prepare_testroot() {
-       OLDPWD="`pwd`"
-       PREFIX="LVMTEST$$"
-
-       trap_teardown
-       TESTDIR=$($abs_srcdir/mkdtemp ${LVM_TEST_DIR-$(pwd)} $PREFIX.XXXXXXXXXX) \
-               || { echo "failed to create temporary directory in ${LVM_TEST_DIR-$(pwd)}"; exit 1; }
-
-       export LVM_SYSTEM_DIR=$TESTDIR/etc
-       export DM_DEV_DIR=$TESTDIR/dev
-       mkdir $LVM_SYSTEM_DIR $DM_DEV_DIR $DM_DEV_DIR/mapper $TESTDIR/lib
-
-       cd $TESTDIR
-
-       for i in `find $abs_top_builddir/daemons/dmeventd/plugins/ -name \*.so`; do
-               echo Setting up symlink from $i to $TESTDIR/lib
-               ln -s $i $TESTDIR/lib
-       done
-}
-
-teardown_devs() {
-       test -n "$PREFIX" && {
-               rm -rf $TESTDIR/dev/$PREFIX*
-
-               init_udev_transaction
-               while dmsetup table | grep -q ^$PREFIX; do
-                       for s in `dmsetup info -c -o name --noheading | grep ^$PREFIX`; do
-                               umount -fl $DM_DEV_DIR/mapper/$s || true
-                               dmsetup remove $s >& /dev/null || true
-                       done
-               done
-               finish_udev_transaction
-
-       }
-
-       # NOTE: SCSI_DEBUG_DEV test must come before the LOOP test because
-       # prepare_scsi_debug_dev() also sets LOOP to short-circuit prepare_loop()
-       if [ -n "$SCSI_DEBUG_DEV" ] ; then
-               modprobe -r scsi_debug
-       else
-               test -n "$LOOP" && losetup -d $LOOP
-               test -n "$LOOPFILE" && rm -f $LOOPFILE
-       fi
-       unset devs # devs is set in prepare_devs()
-       unset LOOP
-}
-
-teardown() {
-       echo $LOOP
-       echo $PREFIX
-
-       test -n "$LOCAL_CLVMD" && {
-               kill "$LOCAL_CLVMD"
-               sleep .1
-               kill -9 "$LOCAL_CLVMD" || true
-       }
-
-       test -n "$LOCAL_DMEVENTD" && kill -9 "$LOCAL_DMEVENTD"
-
-       teardown_devs
-
-       test -n "$TESTDIR" && {
-               cd $OLDPWD
-               rm -rf $TESTDIR || echo BLA
-       }
-}
-
-trap_teardown() {
-       trap 'set +vx; STACKTRACE; set -vx' ERR
-       trap 'aux teardown' EXIT # don't forget to clean up
-}
-
-make_ioerror() {
-       echo 0 10000000 error | dmsetup create ioerror
-       ln -s $DM_DEV_DIR/mapper/ioerror $DM_DEV_DIR/ioerror
-}
-
-prepare_loop() {
-       size=$1
-       test -n "$size" || size=32
-
-       # skip if prepare_scsi_debug_dev() was used
-       if [ -n "$SCSI_DEBUG_DEV" -a -n "$LOOP" ]; then
-               return 0
-       fi
-
-       test -z "$LOOP"
-       test -n "$DM_DEV_DIR"
-
-       trap_teardown
-
-       for i in 0 1 2 3 4 5 6 7; do
-               test -e $DM_DEV_DIR/loop$i || mknod $DM_DEV_DIR/loop$i b 7 $i
-       done
-
-       LOOPFILE="$PWD/test.img"
-       dd if=/dev/zero of="$LOOPFILE" bs=$((1024*1024)) count=0 seek=$(($size-1))
-       if LOOP=`losetup -s -f "$LOOPFILE" 2>/dev/null`; then
-               return 0
-       elif LOOP=`losetup -f` && losetup $LOOP "$LOOPFILE"; then
-               # no -s support
-               return 0
-       else
-               # no -f support 
-               # Iterate through $DM_DEV_DIR/loop{,/}{0,1,2,3,4,5,6,7}
-               for slash in '' /; do
-                       for i in 0 1 2 3 4 5 6 7; do
-                               local dev=$DM_DEV_DIR/loop$slash$i
-                               ! losetup $dev >/dev/null 2>&1 || continue
-                               # got a free
-                               losetup "$dev" "$LOOPFILE"
-                               LOOP=$dev
-                               break
-                       done
-                       if [ -n "$LOOP" ]; then 
-                               break
-                       fi
-               done
-               test -n "$LOOP" # confirm or fail
-               return 0
-       fi
-       exit 1 # should not happen
-}
-
-# A drop-in replacement for prepare_loop() that uses scsi_debug to create
-# a ramdisk-based SCSI device upon which all LVM devices will be created
-# - scripts must take care not to use a DEV_SIZE that will enduce OOM-killer
-prepare_scsi_debug_dev()
-{
-    local DEV_SIZE="$1"
-    shift
-    local SCSI_DEBUG_PARAMS="$@"
-
-    test -n "$SCSI_DEBUG_DEV" && return 0
-    test -z "$LOOP"
-    test -n "$DM_DEV_DIR"
-
-    trap_teardown
-
-    # Skip test if awk isn't available (required for get_sd_devs_)
-    which awk || exit 200
-
-    # Skip test if scsi_debug module is unavailable or is already in use
-    modprobe --dry-run scsi_debug || exit 200
-    lsmod | grep -q scsi_debug && exit 200
-
-    # Create the scsi_debug device and determine the new scsi device's name
-    # NOTE: it will _never_ make sense to pass num_tgts param;
-    # last param wins.. so num_tgts=1 is imposed
-    modprobe scsi_debug dev_size_mb=$DEV_SIZE $SCSI_DEBUG_PARAMS num_tgts=1 || exit 200
-    sleep 2 # allow for async Linux SCSI device registration
-
-    local DEBUG_DEV=/dev/$(grep -H scsi_debug /sys/block/*/device/model | cut -f4 -d /)
-    [ -b $DEBUG_DEV ] || exit 1 # should not happen
-
-    # Create symlink to scsi_debug device in $DM_DEV_DIR
-    SCSI_DEBUG_DEV=$DM_DEV_DIR/$(basename $DEBUG_DEV)
-    # Setting $LOOP provides means for prepare_devs() override
-    LOOP=$SCSI_DEBUG_DEV
-    ln -snf $DEBUG_DEV $SCSI_DEBUG_DEV
-    return 0
-}
-
-cleanup_scsi_debug_dev()
-{
-    aux teardown_devs
-    unset SCSI_DEBUG_DEV
-    unset LOOP
-}
-
-prepare_devs() {
-       local n="$1"
-       test -z "$n" && n=3
-       local devsize="$2"
-       test -z "$devsize" && devsize=34
-       local pvname="$3"
-       test -z "$pvname" && pvname="pv"
-
-       prepare_loop $(($n*$devsize))
-
-       if ! loopsz=`blockdev --getsz $LOOP 2>/dev/null`; then
-               loopsz=`blockdev --getsize $LOOP 2>/dev/null`
-       fi
-
-       local size=$(($loopsz/$n))
-
-       init_udev_transaction
-       for i in `seq 1 $n`; do
-               local name="${PREFIX}$pvname$i"
-               local dev="$DM_DEV_DIR/mapper/$name"
-               eval "dev$i=$dev"
-               devs="$devs $dev"
-               echo 0 $size linear $LOOP $((($i-1)*$size)) > $name.table
-               dmsetup create $name $name.table
-       done
-       finish_udev_transaction
-
-       for i in `seq 1 $n`; do
-               local name="${PREFIX}$pvname$i"
-               dmsetup info -c $name
-       done
-       for i in `seq 1 $n`; do
-               local name="${PREFIX}$pvname$i"
-               dmsetup table $name
-       done
-}
-
-disable_dev() {
-
-       init_udev_transaction
-       for dev in "$@"; do
-        # first we make the device inaccessible
-               echo 0 10000000 error | dmsetup load $dev
-               dmsetup resume $dev
-        # now let's try to get rid of it if it's unused
-        #dmsetup remove $dev
-       done
-       finish_udev_transaction
-
-}
-
-enable_dev() {
-
-       init_udev_transaction
-       for dev in "$@"; do
-               local name=`echo "$dev" | sed -e 's,.*/,,'`
-               dmsetup create $name $name.table || dmsetup load $name $name.table
-               dmsetup resume $dev
-       done
-       finish_udev_transaction
-}
-
-backup_dev() {
-       for dev in "$@"; do
-               dd if=$dev of=$dev.backup bs=1024
-       done
-}
-
-restore_dev() {
-       for dev in "$@"; do
-               test -e $dev.backup || {
-                       echo "Internal error: $dev not backed up, can't restore!"
-                       exit 1
-               }
-               dd of=$dev if=$dev.backup bs=1024
-       done
-}
-
-prepare_pvs() {
-       prepare_devs "$@"
-       pvcreate -ff $devs
-}
-
-prepare_vg() {
-       vgremove -ff $vg || true
-       teardown_devs
-
-       prepare_pvs "$@"
-       vgcreate -c n $vg $devs
-       pvs -v
-}
-
-prepare_lvmconf() {
-       local filter="$1"
-       test -z "$filter" && \
-               filter='[ "a/dev\/mirror/", "a/dev\/mapper\/.*pv[0-9_]*$/", "r/.*/" ]'
-        locktype=
-       if test -z "$LVM_TEST_CONFIG_SNAPSHOT_AUTOEXTEND"; then
-               LVM_TEST_CONFIG_SNAPSHOT_AUTOEXTEND="
-    snapshot_autoextend_percent = 50
-    snapshot_autoextend_threshold = 50"
-       fi
-       if test -n "$LVM_TEST_LOCKING"; then locktype="locking_type = $LVM_TEST_LOCKING"; fi
-       cat > $TESTDIR/etc/lvm.conf.new <<-EOF
-  $LVM_TEST_CONFIG
-  devices {
-    dir = "$DM_DEV_DIR"
-    scan = "$DM_DEV_DIR"
-    filter = $filter
-    cache_dir = "$TESTDIR/etc"
-    sysfs_scan = 0
-    default_data_alignment = 1
-    $LVM_TEST_CONFIG_DEVICES
-  }
-  log {
-    syslog = 0
-    indent = 1
-    level = 9
-    file = "$TESTDIR/debug.log"
-    overwrite = 1
-    activation = 1
-  }
-  backup {
-    backup = 0
-    archive = 0
-  }
-  global {
-    abort_on_internal_errors = 1
-    library_dir = "$TESTDIR/lib"
-    locking_dir = "$TESTDIR/var/lock/lvm"
-    $locktype
-    si_unit_consistency = 1
-    fallback_to_local_locking = 0
-  }
-  activation {
-    udev_sync = 1
-    udev_rules = 1
-    polling_interval = 0
-    $LVM_TEST_CONFIG_SNAPSHOT_AUTOEXTEND
-  }
-EOF
-       # FIXME remove this workaround after mmap & truncating file problems solved
-       mv -f $TESTDIR/etc/lvm.conf.new $TESTDIR/etc/lvm.conf
-       cat $TESTDIR/etc/lvm.conf
-}
-
-prepare() {
-       ulimit -c unlimited
-       # FIXME any way to set this just for our children?
-       # echo 1 > /proc/sys/kernel/core_uses_pid
-       prepare_testroot
-       prepare_lvmconf
-       prepare_clvmd
-
-       # set up some default names
-       vg=${PREFIX}vg
-       vg1=${PREFIX}vg1
-       vg2=${PREFIX}vg2
-       lv=LV
-       lv1=LV1
-       lv2=LV2
-       lv3=LV3
-       lv4=LV4
-}
-
-apitest() {
-       t=$1
-        shift
-       test -x $abs_top_builddir/test/api/$t.t || exit 200
-       $abs_top_builddir/test/api/$t.t "$@"
-}
-
-api() {
-       test -x $abs_top_builddir/test/api/wrapper || exit 200
-       $abs_top_builddir/test/api/wrapper "$@"
-}
-
-LANG=C
-LC_ALL=C
-TZ=UTC
-unset CDPATH
-
-. ./init.sh || { echo >&2 you must run make first; exit 1; }
-. ./lvm-utils.sh
-
-set -vexE -o pipefail
-aux prepare
diff --git a/test/unit/Makefile.in b/test/unit/Makefile.in
new file mode 100644 (file)
index 0000000..740eb14
--- /dev/null
@@ -0,0 +1,33 @@
+# Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# 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
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = @top_builddir@
+
+VPATH = $(srcdir)
+ifeq ("@TESTING@", "yes")
+SOURCES = bitset_t.c matcher_t.c config_t.c string_t.c run.c
+TARGETS = run
+endif
+
+include $(top_builddir)/make.tmpl
+ifeq ("$(TESTING)", "yes")
+LDLIBS += -ldevmapper @CUNIT_LIBS@
+CFLAGS += @CUNIT_CFLAGS@
+
+check: unit
+
+unit: $(TARGETS)
+       @echo Running unit tests
+       LD_LIBRARY_PATH=$(top_builddir)/libdm ./$(TARGETS)
+endif
diff --git a/test/unit/bitset_t.c b/test/unit/bitset_t.c
new file mode 100644 (file)
index 0000000..499de32
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * 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 "libdevmapper.h"
+#include <CUnit/CUnit.h>
+
+int bitset_init(void);
+int bitset_fini(void);
+
+enum {
+        NR_BITS = 137
+};
+
+static struct dm_pool *mem;
+
+int bitset_init(void) {
+       mem = dm_pool_create("bitset test", 1024);
+       return mem == NULL;
+}
+
+int bitset_fini(void) {
+       dm_pool_destroy(mem);
+       return 0;
+}
+
+static void test_get_next(void)
+{
+        int i, j, last = 0, first;
+        dm_bitset_t bs = dm_bitset_create(mem, NR_BITS);
+
+        for (i = 0; i < NR_BITS; i++)
+                CU_ASSERT(!dm_bit(bs, i));
+
+        for (i = 0, j = 1; i < NR_BITS; i += j, j++)
+                dm_bit_set(bs, i);
+
+        first = 1;
+        for (i = 0, j = 1; i < NR_BITS; i += j, j++) {
+                if (first) {
+                        last = dm_bit_get_first(bs);
+                        first = 0;
+                } else
+                        last = dm_bit_get_next(bs, last);
+
+                CU_ASSERT(last == i);
+        }
+
+        CU_ASSERT(dm_bit_get_next(bs, last) == -1);
+}
+
+static void bit_flip(dm_bitset_t bs, int bit)
+{
+        int old = dm_bit(bs, bit);
+        if (old)
+                dm_bit_clear(bs, bit);
+        else
+                dm_bit_set(bs, bit);
+}
+
+static void test_equal(void)
+{
+        dm_bitset_t bs1 = dm_bitset_create(mem, NR_BITS);
+        dm_bitset_t bs2 = dm_bitset_create(mem, NR_BITS);
+
+        int i, j;
+        for (i = 0, j = 1; i < NR_BITS; i += j, j++) {
+                dm_bit_set(bs1, i);
+                dm_bit_set(bs2, i);
+        }
+
+        CU_ASSERT(dm_bitset_equal(bs1, bs2));
+        CU_ASSERT(dm_bitset_equal(bs2, bs1));
+
+        for (i = 0; i < NR_BITS; i++) {
+                bit_flip(bs1, i);
+                CU_ASSERT(!dm_bitset_equal(bs1, bs2));
+                CU_ASSERT(!dm_bitset_equal(bs2, bs1));
+
+                CU_ASSERT(dm_bitset_equal(bs1, bs1)); /* comparing with self */
+                bit_flip(bs1, i);
+        }
+}
+
+static void test_and(void)
+{
+        dm_bitset_t bs1 = dm_bitset_create(mem, NR_BITS);
+        dm_bitset_t bs2 = dm_bitset_create(mem, NR_BITS);
+        dm_bitset_t bs3 = dm_bitset_create(mem, NR_BITS);
+
+        int i, j;
+        for (i = 0, j = 1; i < NR_BITS; i += j, j++) {
+                dm_bit_set(bs1, i);
+                dm_bit_set(bs2, i);
+        }
+
+        dm_bit_and(bs3, bs1, bs2);
+
+        CU_ASSERT(dm_bitset_equal(bs1, bs2));
+        CU_ASSERT(dm_bitset_equal(bs1, bs3));
+        CU_ASSERT(dm_bitset_equal(bs2, bs3));
+
+        dm_bit_clear_all(bs1);
+        dm_bit_clear_all(bs2);
+
+        for (i = 0; i < NR_BITS; i++) {
+                if (i % 2)
+                        dm_bit_set(bs1, i);
+                else
+                        dm_bit_set(bs2, i);
+        }
+
+        dm_bit_and(bs3, bs1, bs2);
+        for (i = 0; i < NR_BITS; i++)
+                CU_ASSERT(!dm_bit(bs3, i));
+}
+
+CU_TestInfo bitset_list[] = {
+       { (char*)"get_next", test_get_next },
+       { (char*)"equal", test_equal },
+       { (char*)"and", test_and },
+       CU_TEST_INFO_NULL
+};
diff --git a/test/unit/config_t.c b/test/unit/config_t.c
new file mode 100644 (file)
index 0000000..9a8b693
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * 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 "libdevmapper.h"
+#include <CUnit/CUnit.h>
+
+int config_init(void);
+int config_fini(void);
+
+static struct dm_pool *mem;
+
+int config_init(void) {
+       mem = dm_pool_create("config test", 1024);
+       return mem == NULL;
+}
+
+int config_fini(void) {
+       dm_pool_destroy(mem);
+       return 0;
+}
+
+static const char *conf =
+       "id = \"yada-yada\"\n"
+       "seqno = 15\n"
+       "status = [\"READ\", \"WRITE\"]\n"
+       "flags = []\n"
+       "extent_size = 8192\n"
+       "physical_volumes {\n"
+       "    pv0 {\n"
+       "        id = \"abcd-efgh\"\n"
+       "    }\n"
+       "    pv1 {\n"
+       "        id = \"bbcd-efgh\"\n"
+       "    }\n"
+       "    pv2 {\n"
+       "        id = \"cbcd-efgh\"\n"
+       "    }\n"
+       "}\n";
+
+static const char *overlay =
+       "id = \"yoda-soda\"\n"
+       "flags = [\"FOO\"]\n"
+       "physical_volumes {\n"
+       "    pv1 {\n"
+       "        id = \"hgfe-dcba\"\n"
+       "    }\n"
+       "    pv3 {\n"
+       "        id = \"dbcd-efgh\"\n"
+       "    }\n"
+       "}\n";
+
+static void test_parse(void)
+{
+       struct dm_config_tree *tree = dm_config_from_string(conf);
+       const struct dm_config_value *value;
+
+       CU_ASSERT((long) tree);
+       CU_ASSERT(dm_config_has_node(tree->root, "id"));
+       CU_ASSERT(dm_config_has_node(tree->root, "physical_volumes"));
+       CU_ASSERT(dm_config_has_node(tree->root, "physical_volumes/pv0"));
+       CU_ASSERT(dm_config_has_node(tree->root, "physical_volumes/pv0/id"));
+
+       CU_ASSERT(!strcmp(dm_config_find_str(tree->root, "id", "foo"), "yada-yada"));
+       CU_ASSERT(!strcmp(dm_config_find_str(tree->root, "idt", "foo"), "foo"));
+
+       CU_ASSERT(!strcmp(dm_config_find_str(tree->root, "physical_volumes/pv0/bb", "foo"), "foo"));
+       CU_ASSERT(!strcmp(dm_config_find_str(tree->root, "physical_volumes/pv0/id", "foo"), "abcd-efgh"));
+
+       CU_ASSERT(!dm_config_get_uint32(tree->root, "id", NULL));
+       CU_ASSERT(dm_config_get_uint32(tree->root, "extent_size", NULL));
+
+       /* FIXME: Currently everything parses as a list, even if it's not */
+       // CU_ASSERT(!dm_config_get_list(tree->root, "id", NULL));
+       // CU_ASSERT(!dm_config_get_list(tree->root, "extent_size", NULL));
+
+       CU_ASSERT(dm_config_get_list(tree->root, "flags", &value));
+       CU_ASSERT(value->next == NULL); /* an empty list */
+       CU_ASSERT(dm_config_get_list(tree->root, "status", &value));
+       CU_ASSERT(value->next != NULL); /* a non-empty list */
+
+       dm_config_destroy(tree);
+}
+
+static void test_clone(void)
+{
+       struct dm_config_tree *tree = dm_config_from_string(conf);
+       struct dm_config_node *n = dm_config_clone_node(tree, tree->root, 1);
+       const struct dm_config_value *value;
+
+       /* Check that the nodes are actually distinct. */
+       CU_ASSERT(n != tree->root);
+       CU_ASSERT(n->sib != tree->root->sib);
+       CU_ASSERT(dm_config_find_node(n, "physical_volumes") != NULL);
+       CU_ASSERT(dm_config_find_node(tree->root, "physical_volumes") != NULL);
+       CU_ASSERT(dm_config_find_node(n, "physical_volumes") != dm_config_find_node(tree->root, "physical_volumes"));
+
+       CU_ASSERT(dm_config_has_node(n, "id"));
+       CU_ASSERT(dm_config_has_node(n, "physical_volumes"));
+       CU_ASSERT(dm_config_has_node(n, "physical_volumes/pv0"));
+       CU_ASSERT(dm_config_has_node(n, "physical_volumes/pv0/id"));
+
+       CU_ASSERT(!strcmp(dm_config_find_str(n, "id", "foo"), "yada-yada"));
+       CU_ASSERT(!strcmp(dm_config_find_str(n, "idt", "foo"), "foo"));
+
+       CU_ASSERT(!strcmp(dm_config_find_str(n, "physical_volumes/pv0/bb", "foo"), "foo"));
+       CU_ASSERT(!strcmp(dm_config_find_str(n, "physical_volumes/pv0/id", "foo"), "abcd-efgh"));
+
+       CU_ASSERT(!dm_config_get_uint32(n, "id", NULL));
+       CU_ASSERT(dm_config_get_uint32(n, "extent_size", NULL));
+
+       /* FIXME: Currently everything parses as a list, even if it's not */
+       // CU_ASSERT(!dm_config_get_list(tree->root, "id", NULL));
+       // CU_ASSERT(!dm_config_get_list(tree->root, "extent_size", NULL));
+
+       CU_ASSERT(dm_config_get_list(n, "flags", &value));
+       CU_ASSERT(value->next == NULL); /* an empty list */
+       CU_ASSERT(dm_config_get_list(n, "status", &value));
+       CU_ASSERT(value->next != NULL); /* a non-empty list */
+
+       dm_config_destroy(tree);
+}
+
+static void test_cascade(void)
+{
+       struct dm_config_tree *t1 = dm_config_from_string(conf),
+                             *t2 = dm_config_from_string(overlay),
+                             *tree = dm_config_insert_cascaded_tree(t2, t1);
+
+       CU_ASSERT(!strcmp(dm_config_tree_find_str(tree, "id", "foo"), "yoda-soda"));
+       CU_ASSERT(!strcmp(dm_config_tree_find_str(tree, "idt", "foo"), "foo"));
+
+       CU_ASSERT(!strcmp(dm_config_tree_find_str(tree, "physical_volumes/pv0/bb", "foo"), "foo"));
+       CU_ASSERT(!strcmp(dm_config_tree_find_str(tree, "physical_volumes/pv1/id", "foo"), "hgfe-dcba"));
+       CU_ASSERT(!strcmp(dm_config_tree_find_str(tree, "physical_volumes/pv3/id", "foo"), "dbcd-efgh"));
+
+       dm_config_destroy(t1);
+       dm_config_destroy(t2);
+}
+
+CU_TestInfo config_list[] = {
+       { (char*)"parse", test_parse },
+       { (char*)"clone", test_clone },
+       { (char*)"cascade", test_cascade },
+       CU_TEST_INFO_NULL
+};
diff --git a/test/unit/matcher_data.h b/test/unit/matcher_data.h
new file mode 100644 (file)
index 0000000..97dbbfe
--- /dev/null
@@ -0,0 +1,1013 @@
+struct check_item {
+       const char *str;
+       int expected;
+};
+
+static const char *dev_patterns[] = {
+       "loop/[0-9]+",
+       "hd[a-d][0-5]+",
+       NULL
+};
+
+static const char *nonprint_patterns[] = {
+       "foo\x80" "bar",
+       "foo\xc2" "b",
+       "\x80",
+       NULL
+};
+
+static const struct check_item nonprint[] = {
+       { "foo\x2e" "bar", 0 },
+       { "foo\x80" "bar", 3 },
+       { "foo\xc2" "b", 2 },
+       { "\x80", 3 },
+       { NULL, 0 }
+};
+
+static const char *random_patterns[] = {
+       "(((a?)(([Ub]*)|z))((([qr]|X)+)([Qn]*)))+",
+       "[HZejtuw]*",
+       "((B|s)*)|(((([Fv]l)(N+))(([el]|C)(tJ)))?)",
+       "((([Ma]?)|(t*))*)|((([cm]E)|(M?))|(([BE][EV])|([Qj][Mh])))",
+       "(((([bw]*)|([IO]*))((zK)*))|(((pU)|(i|q))|((z?)|([HL]?))))*",
+       "((([Pt]?)|[Tr])?)((Hq)*)",
+       "[HOXcfgikosvwxz]",
+       "[BCEFGHNPTUWfjlprsy]",
+       "((((aD)*)|([Xo]+))+)(([HKn](([Eq]|[JQ])(I*)))*)",
+       "([LNWYeghv]|e)*",
+       "(((y(L*))*)|((([EP]+)(W+))*))*",
+       "U*",
+       "((((R+)(W|[Qr]))|([py]+))+)([LM]*)",
+       "(([DOjx](D(b?)))|([Ke]*))*",
+       "((([ls](c|[FT]))*)([JS]*))*",
+       "((l?)|(([Gz]+)|(D*)))*",
+       "[ABgjn]",
+       "(((q|[dg])?)|([Uk]*))((([Fl]?)|([Ry]+))|(([IR]|c)|(T?)))",
+       "((([an]|P)|[Jw])((a*)|(m*)))*",
+       "((((R[ht])(h+))?)|(([pz](n?))+))+",
+       "(((([Dc]b)([Sp][Ii]))|((k|F)*))|[Uiovz])*",
+       "[Res]*",
+       "[Zl]|a",
+       "^[ANZdf]$",
+       "[En]|(((Q+)(U+))([pt]*))",
+       "[ADEIMQUWXZhklrsvz]",
+       "(((S(y*))*)|(j*))*",
+       "n*",
+       "[NUau]*",
+       "((((Z*)(D|[Nd]))|(([np]|B)+))|(([Xy][Fi])*))+",
+       "((([EZ]?)|(d[HR]))*)((([Hg]|q)(P+))*)",
+       "q",
+       "((m*)|(p|B))|((((x?)|(t+))(([Sb][PX])(O|[HM])))+)",
+       "((((A*)(z[RS]))*)|(((z+)(Q*))+))*",
+       "(((M*)([Uu]*))+)|[Uk]",
+       "[imv]",
+       "[GLSchtw](([Yw]((F[Dd])|([Tw]+)))?)",
+       "([MOZj]*)(S|[Wknr])",
+       "((G|q)*)[BHKN]",
+       "((((NW)|([Ao]?))|((l|[UV])+))+)|((i|(z*))*)",
+       "((((Z+)|([IR]?))|(L*))|([JKQ]+))+",
+       "([Bdin](S*))+",
+       "[HLNSTp]*",
+       "(((J*)([Bq]|[Yu]))*)|([Kv]*)",
+       "(((([BJ]|[Zy])(wI))*)(y*))+",
+       "(((hF)+)|(H*))*",
+       "((([QU][Pj])([GQ]?))+)|[PWo]",
+       "(((([cq][BX])?)|((f[DI])*))*)(([GM]*)[SVYr])",
+       "(([Zt]*)|((qx)|(([BV]+)(f?))))*",
+       "[ILWYhsx]*",
+       "(([Uy]*)|[sv])|([NSc]*)",
+       "((c*)|([JUfhy]?))+",
+       "(((q*)([So]*))(((g[jq])(j?))+))*",
+       "((b+)|(((T+)([fw]T))?))*",
+       "((([DS]?)|([Th]|u))(Q*))*",
+       "[FKLX]|((([fw](L?))(([gq]*)|(O?)))?)",
+       "((([HZ]+)u)*)|[APWijn]",
+       "(e*)|(((v?)|((J+)(Hb)))?)",
+       "(e|((w+)f))*",
+       "[BEHKPQVdelnqy]",
+       "((((B|N)(s*))|[Rr])(((g?)|([rv]+))+))+",
+       "(((s*)|(K*))([AP]G))*",
+       "[CELTp]",
+       "(([Fq]?)|([Al]+))*",
+       "((((r?)|(y[jx]))|([mp]*))+)|((B(S*))*)",
+       "((([Eq]+)|(Y[ds]))|(x|(i|[Ku])))[IJNrvy]",
+       "((([NO]*)[Ix])+)([Jenq]+)",
+       "(((([HP]*)(j|y))*)[Ylqvy])*",
+       "[PTv]+",
+       "[AINSZhpx]|([EOYZ]*)",
+       "([ABCFQv]*)((([Zx]|h)+)|([ej]*))",
+       "((([pr]*)|(([Dq]|p)|(H?)))?)([NRUXmoq]*)",
+       "(([er]*)|([mx]*))(((nV)([am]?))+)",
+       "[BHPRlpu]",
+       "(((([Ah]|[tx])|(e|[uy]))?)((([fl]+)([Vz]|v))*))*",
+       "[AGdm]",
+       "(((K*)^(O*)$)|(B?))*",
+       "((([Ks]|[Ka])*)|([FSTab]?))?",
+       "(([kw]+)[ei])(([Hy]*)(([Mc]*)|(G|f)))",
+       "((((e*)|(Zf))|(R|[nq]))((([Jz]v)([Rj]+))+))*",
+       "(((a?)|(e?))(([Uc]*)(S+)))*",
+       "((((E+)([MZ]?))+)|(((s|[Az])|z)*))?",
+       "((((i[MO])*)|((LH)*))|(((BA)|([AI]+))|[Ug]))*",
+       "[EGHILcho]*",
+       "(((Z[vw])?)((z|g)+))(((H|U)([iv]Q))|([qw]?))",
+       "(([ehmr]|((L[Uw])*))+)((a+)I)",
+       "[EKNSWYagj](((v|[TX])|([Uk]+))*)",
+       "(((R[Mo])|(O*))|([Fm]|([qw]*)))((m*)|((S|[Ki])?))",
+       "((((kP)|c)?)((([do]+)|([Gi]?))*))*",
+       "((^(B|W)$|([Ww]+))([no]*))|((([iv]?)|(M*))|((x|L)?))",
+       "[AEGPRSbcfhsy]",
+       "[Wbcf]|((([MO]?)|([NT]|m))(([Oo]?)([Wg]*)))",
+       "(((YZ)*)[PQVei])*",
+       "[GJKYt][AEGWdegmnt]",
+       "^[CDEGJKNUVYZagkv]$",
+       "([DPWbx]*)|(((q|B)|(P|u))((M[Bq])*))",
+       "[FHIJRTVYZdiorsuvz]*",
+       "([MWoqvz]*)|^(l*)",
+       "(((I|[Rx])*)((X[Mf])([Xa]L)))([Ha]|([HY]*))",
+       "(((l|[Sd])*)((([Ix]+)|([XY]?))(Z*)))+",
+       NULL
+};
+
+struct check_item devices[] = {
+       { "/dev", 0 },
+       { "/dev/.devfsd", 0 },
+       { "/dev/cpu", 0 },
+       { "/dev/cpu/mtrr", 0 },
+       { "/dev/netlink", 0 },
+       { "/dev/netlink/route", 0 },
+       { "/dev/netlink/skip", 0 },
+       { "/dev/netlink/USERSOCK", 0 },
+       { "/dev/netlink/fwmonitor", 0 },
+       { "/dev/netlink/ARPD", 0 },
+       { "/dev/netlink/ROUTE6", 0 },
+       { "/dev/netlink/IP6_FW", 0 },
+       { "/dev/netlink/tap0", 0 },
+       { "/dev/netlink/tap1", 0 },
+       { "/dev/netlink/tap2", 0 },
+       { "/dev/netlink/tap3", 0 },
+       { "/dev/netlink/tap4", 0 },
+       { "/dev/netlink/tap5", 0 },
+       { "/dev/netlink/tap6", 0 },
+       { "/dev/netlink/tap7", 0 },
+       { "/dev/netlink/tap8", 0 },
+       { "/dev/netlink/tap9", 0 },
+       { "/dev/netlink/tap10", 0 },
+       { "/dev/netlink/tap11", 0 },
+       { "/dev/netlink/tap12", 0 },
+       { "/dev/netlink/tap13", 0 },
+       { "/dev/netlink/tap14", 0 },
+       { "/dev/netlink/tap15", 0 },
+       { "/dev/shm", 0 },
+       { "/dev/mem", 0 },
+       { "/dev/kmem", 0 },
+       { "/dev/null", 0 },
+       { "/dev/port", 0 },
+       { "/dev/zero", 0 },
+       { "/dev/full", 0 },
+       { "/dev/random", 0 },
+       { "/dev/urandom", 0 },
+       { "/dev/tty", 0 },
+       { "/dev/console", 0 },
+       { "/dev/vc", 0 },
+       { "/dev/vc/1", 0 },
+       { "/dev/vc/2", 0 },
+       { "/dev/vc/3", 0 },
+       { "/dev/vc/4", 0 },
+       { "/dev/vc/5", 0 },
+       { "/dev/vc/6", 0 },
+       { "/dev/vc/7", 0 },
+       { "/dev/vc/8", 0 },
+       { "/dev/vc/9", 0 },
+       { "/dev/vc/10", 0 },
+       { "/dev/vc/11", 0 },
+       { "/dev/vc/12", 0 },
+       { "/dev/vc/13", 0 },
+       { "/dev/vc/14", 0 },
+       { "/dev/vc/15", 0 },
+       { "/dev/vc/16", 0 },
+       { "/dev/vc/17", 0 },
+       { "/dev/vc/18", 0 },
+       { "/dev/vc/19", 0 },
+       { "/dev/vc/20", 0 },
+       { "/dev/vc/21", 0 },
+       { "/dev/vc/22", 0 },
+       { "/dev/vc/23", 0 },
+       { "/dev/vc/24", 0 },
+       { "/dev/vc/25", 0 },
+       { "/dev/vc/26", 0 },
+       { "/dev/vc/27", 0 },
+       { "/dev/vc/28", 0 },
+       { "/dev/vc/29", 0 },
+       { "/dev/vc/30", 0 },
+       { "/dev/vc/31", 0 },
+       { "/dev/vc/32", 0 },
+       { "/dev/vc/33", 0 },
+       { "/dev/vc/34", 0 },
+       { "/dev/vc/35", 0 },
+       { "/dev/vc/36", 0 },
+       { "/dev/vc/37", 0 },
+       { "/dev/vc/38", 0 },
+       { "/dev/vc/39", 0 },
+       { "/dev/vc/40", 0 },
+       { "/dev/vc/41", 0 },
+       { "/dev/vc/42", 0 },
+       { "/dev/vc/43", 0 },
+       { "/dev/vc/44", 0 },
+       { "/dev/vc/45", 0 },
+       { "/dev/vc/46", 0 },
+       { "/dev/vc/47", 0 },
+       { "/dev/vc/48", 0 },
+       { "/dev/vc/49", 0 },
+       { "/dev/vc/50", 0 },
+       { "/dev/vc/51", 0 },
+       { "/dev/vc/52", 0 },
+       { "/dev/vc/53", 0 },
+       { "/dev/vc/54", 0 },
+       { "/dev/vc/55", 0 },
+       { "/dev/vc/56", 0 },
+       { "/dev/vc/57", 0 },
+       { "/dev/vc/58", 0 },
+       { "/dev/vc/59", 0 },
+       { "/dev/vc/60", 0 },
+       { "/dev/vc/61", 0 },
+       { "/dev/vc/62", 0 },
+       { "/dev/vc/63", 0 },
+       { "/dev/vc/0", 0 },
+       { "/dev/ptmx", 0 },
+       { "/dev/misc", 0 },
+       { "/dev/misc/psaux", 0 },
+       { "/dev/pty", 0 },
+       { "/dev/pty/m0", 0 },
+       { "/dev/pty/m1", 0 },
+       { "/dev/pty/m2", 0 },
+       { "/dev/pty/m3", 0 },
+       { "/dev/pty/m4", 0 },
+       { "/dev/pty/m5", 0 },
+       { "/dev/pty/m6", 0 },
+       { "/dev/pty/m7", 0 },
+       { "/dev/pty/m8", 0 },
+       { "/dev/pty/m9", 0 },
+       { "/dev/pty/m10", 0 },
+       { "/dev/pty/m11", 0 },
+       { "/dev/pty/m12", 0 },
+       { "/dev/pty/m13", 0 },
+       { "/dev/pty/m14", 0 },
+       { "/dev/pty/m15", 0 },
+       { "/dev/pty/m16", 0 },
+       { "/dev/pty/m17", 0 },
+       { "/dev/pty/m18", 0 },
+       { "/dev/pty/m19", 0 },
+       { "/dev/pty/m20", 0 },
+       { "/dev/pty/m21", 0 },
+       { "/dev/pty/m22", 0 },
+       { "/dev/pty/m23", 0 },
+       { "/dev/pty/m24", 0 },
+       { "/dev/pty/m25", 0 },
+       { "/dev/pty/m26", 0 },
+       { "/dev/pty/m27", 0 },
+       { "/dev/pty/m28", 0 },
+       { "/dev/pty/m29", 0 },
+       { "/dev/pty/m30", 0 },
+       { "/dev/pty/m31", 0 },
+       { "/dev/pty/m32", 0 },
+       { "/dev/pty/m33", 0 },
+       { "/dev/pty/m34", 0 },
+       { "/dev/pty/m35", 0 },
+       { "/dev/pty/m36", 0 },
+       { "/dev/pty/m37", 0 },
+       { "/dev/pty/m38", 0 },
+       { "/dev/pty/m39", 0 },
+       { "/dev/pty/m40", 0 },
+       { "/dev/pty/m41", 0 },
+       { "/dev/pty/m42", 0 },
+       { "/dev/pty/m43", 0 },
+       { "/dev/pty/m44", 0 },
+       { "/dev/pty/m45", 0 },
+       { "/dev/pty/m46", 0 },
+       { "/dev/pty/m47", 0 },
+       { "/dev/pty/m48", 0 },
+       { "/dev/pty/m49", 0 },
+       { "/dev/pty/m50", 0 },
+       { "/dev/pty/m51", 0 },
+       { "/dev/pty/m52", 0 },
+       { "/dev/pty/m53", 0 },
+       { "/dev/pty/m54", 0 },
+       { "/dev/pty/m55", 0 },
+       { "/dev/pty/m56", 0 },
+       { "/dev/pty/m57", 0 },
+       { "/dev/pty/m58", 0 },
+       { "/dev/pty/m59", 0 },
+       { "/dev/pty/m60", 0 },
+       { "/dev/pty/m61", 0 },
+       { "/dev/pty/m62", 0 },
+       { "/dev/pty/m63", 0 },
+       { "/dev/pty/m64", 0 },
+       { "/dev/pty/m65", 0 },
+       { "/dev/pty/m66", 0 },
+       { "/dev/pty/m67", 0 },
+       { "/dev/pty/m68", 0 },
+       { "/dev/pty/m69", 0 },
+       { "/dev/pty/m70", 0 },
+       { "/dev/pty/m71", 0 },
+       { "/dev/pty/m72", 0 },
+       { "/dev/pty/m73", 0 },
+       { "/dev/pty/m74", 0 },
+       { "/dev/pty/m75", 0 },
+       { "/dev/pty/m76", 0 },
+       { "/dev/pty/m77", 0 },
+       { "/dev/pty/m78", 0 },
+       { "/dev/pty/m79", 0 },
+       { "/dev/pty/m80", 0 },
+       { "/dev/pty/m81", 0 },
+       { "/dev/pty/m82", 0 },
+       { "/dev/pty/m83", 0 },
+       { "/dev/pty/m84", 0 },
+       { "/dev/pty/m85", 0 },
+       { "/dev/pty/m86", 0 },
+       { "/dev/pty/m87", 0 },
+       { "/dev/pty/m88", 0 },
+       { "/dev/pty/m89", 0 },
+       { "/dev/pty/m90", 0 },
+       { "/dev/pty/m91", 0 },
+       { "/dev/pty/m92", 0 },
+       { "/dev/pty/m93", 0 },
+       { "/dev/pty/m94", 0 },
+       { "/dev/pty/m95", 0 },
+       { "/dev/pty/m96", 0 },
+       { "/dev/pty/m97", 0 },
+       { "/dev/pty/m98", 0 },
+       { "/dev/pty/m99", 0 },
+       { "/dev/pty/m100", 0 },
+       { "/dev/pty/m101", 0 },
+       { "/dev/pty/m102", 0 },
+       { "/dev/pty/m103", 0 },
+       { "/dev/pty/m104", 0 },
+       { "/dev/pty/m105", 0 },
+       { "/dev/pty/m106", 0 },
+       { "/dev/pty/m107", 0 },
+       { "/dev/pty/m108", 0 },
+       { "/dev/pty/m109", 0 },
+       { "/dev/pty/m110", 0 },
+       { "/dev/pty/m111", 0 },
+       { "/dev/pty/m112", 0 },
+       { "/dev/pty/m113", 0 },
+       { "/dev/pty/m114", 0 },
+       { "/dev/pty/m115", 0 },
+       { "/dev/pty/m116", 0 },
+       { "/dev/pty/m117", 0 },
+       { "/dev/pty/m118", 0 },
+       { "/dev/pty/m119", 0 },
+       { "/dev/pty/m120", 0 },
+       { "/dev/pty/m121", 0 },
+       { "/dev/pty/m122", 0 },
+       { "/dev/pty/m123", 0 },
+       { "/dev/pty/m124", 0 },
+       { "/dev/pty/m125", 0 },
+       { "/dev/pty/m126", 0 },
+       { "/dev/pty/m127", 0 },
+       { "/dev/pty/m128", 0 },
+       { "/dev/pty/m129", 0 },
+       { "/dev/pty/m130", 0 },
+       { "/dev/pty/m131", 0 },
+       { "/dev/pty/m132", 0 },
+       { "/dev/pty/m133", 0 },
+       { "/dev/pty/m134", 0 },
+       { "/dev/pty/m135", 0 },
+       { "/dev/pty/m136", 0 },
+       { "/dev/pty/m137", 0 },
+       { "/dev/pty/m138", 0 },
+       { "/dev/pty/m139", 0 },
+       { "/dev/pty/m140", 0 },
+       { "/dev/pty/m141", 0 },
+       { "/dev/pty/m142", 0 },
+       { "/dev/pty/m143", 0 },
+       { "/dev/pty/m144", 0 },
+       { "/dev/pty/m145", 0 },
+       { "/dev/pty/m146", 0 },
+       { "/dev/pty/m147", 0 },
+       { "/dev/pty/m148", 0 },
+       { "/dev/pty/m149", 0 },
+       { "/dev/pty/m150", 0 },
+       { "/dev/pty/m151", 0 },
+       { "/dev/pty/m152", 0 },
+       { "/dev/pty/m153", 0 },
+       { "/dev/pty/m154", 0 },
+       { "/dev/pty/m155", 0 },
+       { "/dev/pty/m156", 0 },
+       { "/dev/pty/m157", 0 },
+       { "/dev/pty/m158", 0 },
+       { "/dev/pty/m159", 0 },
+       { "/dev/pty/m160", 0 },
+       { "/dev/pty/m161", 0 },
+       { "/dev/pty/m162", 0 },
+       { "/dev/pty/m163", 0 },
+       { "/dev/pty/m164", 0 },
+       { "/dev/pty/m165", 0 },
+       { "/dev/pty/m166", 0 },
+       { "/dev/pty/m167", 0 },
+       { "/dev/pty/m168", 0 },
+       { "/dev/pty/m169", 0 },
+       { "/dev/pty/m170", 0 },
+       { "/dev/pty/m171", 0 },
+       { "/dev/pty/m172", 0 },
+       { "/dev/pty/m173", 0 },
+       { "/dev/pty/m174", 0 },
+       { "/dev/pty/m175", 0 },
+       { "/dev/pty/m176", 0 },
+       { "/dev/pty/m177", 0 },
+       { "/dev/pty/m178", 0 },
+       { "/dev/pty/m179", 0 },
+       { "/dev/pty/m180", 0 },
+       { "/dev/pty/m181", 0 },
+       { "/dev/pty/m182", 0 },
+       { "/dev/pty/m183", 0 },
+       { "/dev/pty/m184", 0 },
+       { "/dev/pty/m185", 0 },
+       { "/dev/pty/m186", 0 },
+       { "/dev/pty/m187", 0 },
+       { "/dev/pty/m188", 0 },
+       { "/dev/pty/m189", 0 },
+       { "/dev/pty/m190", 0 },
+       { "/dev/pty/m191", 0 },
+       { "/dev/pty/m192", 0 },
+       { "/dev/pty/m193", 0 },
+       { "/dev/pty/m194", 0 },
+       { "/dev/pty/m195", 0 },
+       { "/dev/pty/m196", 0 },
+       { "/dev/pty/m197", 0 },
+       { "/dev/pty/m198", 0 },
+       { "/dev/pty/m199", 0 },
+       { "/dev/pty/m200", 0 },
+       { "/dev/pty/m201", 0 },
+       { "/dev/pty/m202", 0 },
+       { "/dev/pty/m203", 0 },
+       { "/dev/pty/m204", 0 },
+       { "/dev/pty/m205", 0 },
+       { "/dev/pty/m206", 0 },
+       { "/dev/pty/m207", 0 },
+       { "/dev/pty/m208", 0 },
+       { "/dev/pty/m209", 0 },
+       { "/dev/pty/m210", 0 },
+       { "/dev/pty/m211", 0 },
+       { "/dev/pty/m212", 0 },
+       { "/dev/pty/m213", 0 },
+       { "/dev/pty/m214", 0 },
+       { "/dev/pty/m215", 0 },
+       { "/dev/pty/m216", 0 },
+       { "/dev/pty/m217", 0 },
+       { "/dev/pty/m218", 0 },
+       { "/dev/pty/m219", 0 },
+       { "/dev/pty/m220", 0 },
+       { "/dev/pty/m221", 0 },
+       { "/dev/pty/m222", 0 },
+       { "/dev/pty/m223", 0 },
+       { "/dev/pty/m224", 0 },
+       { "/dev/pty/m225", 0 },
+       { "/dev/pty/m226", 0 },
+       { "/dev/pty/m227", 0 },
+       { "/dev/pty/m228", 0 },
+       { "/dev/pty/m229", 0 },
+       { "/dev/pty/m230", 0 },
+       { "/dev/pty/m231", 0 },
+       { "/dev/pty/m232", 0 },
+       { "/dev/pty/m233", 0 },
+       { "/dev/pty/m234", 0 },
+       { "/dev/pty/m235", 0 },
+       { "/dev/pty/m236", 0 },
+       { "/dev/pty/m237", 0 },
+       { "/dev/pty/m238", 0 },
+       { "/dev/pty/m239", 0 },
+       { "/dev/pty/m240", 0 },
+       { "/dev/pty/m241", 0 },
+       { "/dev/pty/m242", 0 },
+       { "/dev/pty/m243", 0 },
+       { "/dev/pty/m244", 0 },
+       { "/dev/pty/m245", 0 },
+       { "/dev/pty/m246", 0 },
+       { "/dev/pty/m247", 0 },
+       { "/dev/pty/m248", 0 },
+       { "/dev/pty/m249", 0 },
+       { "/dev/pty/m250", 0 },
+       { "/dev/pty/m251", 0 },
+       { "/dev/pty/m252", 0 },
+       { "/dev/pty/m253", 0 },
+       { "/dev/pty/m254", 0 },
+       { "/dev/pty/m255", 0 },
+       { "/dev/pts", 0 },
+       { "/dev/pts/0", 0 },
+       { "/dev/pts/1", 0 },
+       { "/dev/pts/2", 0 },
+       { "/dev/pts/3", 0 },
+       { "/dev/pts/4", 0 },
+       { "/dev/pts/5", 0 },
+       { "/dev/pts/6", 0 },
+       { "/dev/pts/7", 0 },
+       { "/dev/vcc", 0 },
+       { "/dev/vcc/0", 0 },
+       { "/dev/vcc/a", 0 },
+       { "/dev/vcc/1", 0 },
+       { "/dev/vcc/a1", 0 },
+       { "/dev/vcc/2", 0 },
+       { "/dev/vcc/a2", 0 },
+       { "/dev/vcc/3", 0 },
+       { "/dev/vcc/a3", 0 },
+       { "/dev/vcc/5", 0 },
+       { "/dev/vcc/a5", 0 },
+       { "/dev/vcc/4", 0 },
+       { "/dev/vcc/a4", 0 },
+       { "/dev/vcc/6", 0 },
+       { "/dev/vcc/a6", 0 },
+       { "/dev/vcc/7", 0 },
+       { "/dev/vcc/a7", 0 },
+       { "/dev/tts", 0 },
+       { "/dev/tts/0", 0 },
+       { "/dev/cua", 0 },
+       { "/dev/cua/0", 0 },
+       { "/dev/ide", 0 },
+       { "/dev/ide/host0", 0 },
+       { "/dev/ide/host0/bus0", 0 },
+       { "/dev/ide/host0/bus0/target0", 0 },
+       { "/dev/ide/host0/bus0/target0/lun0", 0 },
+       { "/dev/ide/host0/bus0/target0/lun0/disc", 0 },
+       { "/dev/ide/host0/bus0/target0/lun0/part1", 0 },
+       { "/dev/ide/host0/bus0/target0/lun0/part2", 0 },
+       { "/dev/ide/host0/bus0/target0/lun0/part3", 0 },
+       { "/dev/ide/host0/bus0/target0/lun0/part4", 0 },
+       { "/dev/ide/host0/bus0/target0/lun0/part5", 0 },
+       { "/dev/ide/host0/bus0/target0/lun0/part6", 0 },
+       { "/dev/ide/host0/bus0/target0/lun0/part7", 0 },
+       { "/dev/ide/host0/bus0/target0/lun0/part8", 0 },
+       { "/dev/ide/host0/bus0/target1", 0 },
+       { "/dev/ide/host0/bus0/target1/lun0", 0 },
+       { "/dev/ide/host0/bus0/target1/lun0/disc", 0 },
+       { "/dev/ide/host0/bus0/target1/lun0/part1", 0 },
+       { "/dev/ide/host0/bus1", 0 },
+       { "/dev/ide/host0/bus1/target0", 0 },
+       { "/dev/ide/host0/bus1/target0/lun0", 0 },
+       { "/dev/ide/host0/bus1/target0/lun0/disc", 0 },
+       { "/dev/ide/host0/bus1/target0/lun0/part1", 0 },
+       { "/dev/ide/host0/bus1/target1", 0 },
+       { "/dev/ide/host0/bus1/target1/lun0", 0 },
+       { "/dev/discs", 0 },
+       { "/dev/discs/disc0", 0 },
+       { "/dev/discs/disc1", 0 },
+       { "/dev/discs/disc2", 0 },
+       { "/dev/floppy", 0 },
+       { "/dev/floppy/0u1440", 0 },
+       { "/dev/floppy/0u1680", 0 },
+       { "/dev/floppy/0u1722", 0 },
+       { "/dev/floppy/0u1743", 0 },
+       { "/dev/floppy/0u1760", 0 },
+       { "/dev/floppy/0u1920", 0 },
+       { "/dev/floppy/0u1840", 0 },
+       { "/dev/floppy/0u1600", 0 },
+       { "/dev/floppy/0u360", 0 },
+       { "/dev/floppy/0u720", 0 },
+       { "/dev/floppy/0u820", 0 },
+       { "/dev/floppy/0u830", 0 },
+       { "/dev/floppy/0u1040", 0 },
+       { "/dev/floppy/0u1120", 0 },
+       { "/dev/floppy/0u800", 0 },
+       { "/dev/floppy/0", 0 },
+       { "/dev/loop", 0 },
+       { "/dev/loop/0", 1 },
+       { "/dev/loop/1", 1 },
+       { "/dev/loop/2", 1 },
+       { "/dev/loop/3", 1 },
+       { "/dev/loop/4", 1 },
+       { "/dev/loop/5", 1 },
+       { "/dev/loop/6", 1 },
+       { "/dev/loop/7", 1 },
+       { "/dev/cdroms", 0 },
+       { "/dev/sound", 0 },
+       { "/dev/sound/dsp", 0 },
+       { "/dev/sound/dsp1", 0 },
+       { "/dev/sound/mixer", 0 },
+       { "/dev/sound/midi", 0 },
+       { "/dev/usb", 0 },
+       { "/dev/root", 0 },
+       { "/dev/initctl", 0 },
+       { "/dev/xconsole", 0 },
+       { "/dev/fd", 0 },
+       { "/dev/stdin", 0 },
+       { "/dev/stdout", 0 },
+       { "/dev/stderr", 0 },
+       { "/dev/route", 0 },
+       { "/dev/skip", 0 },
+       { "/dev/USERSOCK", 0 },
+       { "/dev/fwmonitor", 0 },
+       { "/dev/ARPD", 0 },
+       { "/dev/ROUTE6", 0 },
+       { "/dev/IP6_FW", 0 },
+       { "/dev/tap0", 0 },
+       { "/dev/tap1", 0 },
+       { "/dev/tap2", 0 },
+       { "/dev/tap3", 0 },
+       { "/dev/tap4", 0 },
+       { "/dev/tap5", 0 },
+       { "/dev/tap6", 0 },
+       { "/dev/tap7", 0 },
+       { "/dev/tap8", 0 },
+       { "/dev/tap9", 0 },
+       { "/dev/tap10", 0 },
+       { "/dev/tap11", 0 },
+       { "/dev/tap12", 0 },
+       { "/dev/tap13", 0 },
+       { "/dev/tap14", 0 },
+       { "/dev/tap15", 0 },
+       { "/dev/tty1", 0 },
+       { "/dev/tty2", 0 },
+       { "/dev/tty3", 0 },
+       { "/dev/tty4", 0 },
+       { "/dev/tty5", 0 },
+       { "/dev/tty6", 0 },
+       { "/dev/tty7", 0 },
+       { "/dev/tty8", 0 },
+       { "/dev/tty9", 0 },
+       { "/dev/tty10", 0 },
+       { "/dev/tty11", 0 },
+       { "/dev/tty12", 0 },
+       { "/dev/tty13", 0 },
+       { "/dev/tty14", 0 },
+       { "/dev/tty15", 0 },
+       { "/dev/tty16", 0 },
+       { "/dev/tty17", 0 },
+       { "/dev/tty18", 0 },
+       { "/dev/tty19", 0 },
+       { "/dev/tty20", 0 },
+       { "/dev/tty21", 0 },
+       { "/dev/tty22", 0 },
+       { "/dev/tty23", 0 },
+       { "/dev/tty24", 0 },
+       { "/dev/tty25", 0 },
+       { "/dev/tty26", 0 },
+       { "/dev/tty27", 0 },
+       { "/dev/tty28", 0 },
+       { "/dev/tty29", 0 },
+       { "/dev/tty30", 0 },
+       { "/dev/tty31", 0 },
+       { "/dev/tty32", 0 },
+       { "/dev/tty33", 0 },
+       { "/dev/tty34", 0 },
+       { "/dev/tty35", 0 },
+       { "/dev/tty36", 0 },
+       { "/dev/tty37", 0 },
+       { "/dev/tty38", 0 },
+       { "/dev/tty39", 0 },
+       { "/dev/tty40", 0 },
+       { "/dev/tty41", 0 },
+       { "/dev/tty42", 0 },
+       { "/dev/tty43", 0 },
+       { "/dev/tty44", 0 },
+       { "/dev/tty45", 0 },
+       { "/dev/tty46", 0 },
+       { "/dev/tty47", 0 },
+       { "/dev/tty48", 0 },
+       { "/dev/tty49", 0 },
+       { "/dev/tty50", 0 },
+       { "/dev/tty51", 0 },
+       { "/dev/tty52", 0 },
+       { "/dev/tty53", 0 },
+       { "/dev/tty54", 0 },
+       { "/dev/tty55", 0 },
+       { "/dev/tty56", 0 },
+       { "/dev/tty57", 0 },
+       { "/dev/tty58", 0 },
+       { "/dev/tty59", 0 },
+       { "/dev/tty60", 0 },
+       { "/dev/tty61", 0 },
+       { "/dev/tty62", 0 },
+       { "/dev/tty63", 0 },
+       { "/dev/tty0", 0 },
+       { "/dev/psaux", 0 },
+       { "/dev/ptyp0", 0 },
+       { "/dev/ptyp1", 0 },
+       { "/dev/ptyp2", 0 },
+       { "/dev/ptyp3", 0 },
+       { "/dev/ptyp4", 0 },
+       { "/dev/ptyp5", 0 },
+       { "/dev/ptyp6", 0 },
+       { "/dev/ptyp7", 0 },
+       { "/dev/ptyp8", 0 },
+       { "/dev/ptyp9", 0 },
+       { "/dev/ptypa", 0 },
+       { "/dev/ptypb", 0 },
+       { "/dev/ptypc", 0 },
+       { "/dev/ptypd", 0 },
+       { "/dev/ptype", 0 },
+       { "/dev/ptypf", 0 },
+       { "/dev/ptyq0", 0 },
+       { "/dev/ptyq1", 0 },
+       { "/dev/ptyq2", 0 },
+       { "/dev/ptyq3", 0 },
+       { "/dev/ptyq4", 0 },
+       { "/dev/ptyq5", 0 },
+       { "/dev/ptyq6", 0 },
+       { "/dev/ptyq7", 0 },
+       { "/dev/ptyq8", 0 },
+       { "/dev/ptyq9", 0 },
+       { "/dev/ptyqa", 0 },
+       { "/dev/ptyqb", 0 },
+       { "/dev/ptyqc", 0 },
+       { "/dev/ptyqd", 0 },
+       { "/dev/ptyqe", 0 },
+       { "/dev/ptyqf", 0 },
+       { "/dev/ptyr0", 0 },
+       { "/dev/ptyr1", 0 },
+       { "/dev/ptyr2", 0 },
+       { "/dev/ptyr3", 0 },
+       { "/dev/ptyr4", 0 },
+       { "/dev/ptyr5", 0 },
+       { "/dev/ptyr6", 0 },
+       { "/dev/ptyr7", 0 },
+       { "/dev/ptyr8", 0 },
+       { "/dev/ptyr9", 0 },
+       { "/dev/ptyra", 0 },
+       { "/dev/ptyrb", 0 },
+       { "/dev/ptyrc", 0 },
+       { "/dev/ptyrd", 0 },
+       { "/dev/ptyre", 0 },
+       { "/dev/ptyrf", 0 },
+       { "/dev/ptys0", 0 },
+       { "/dev/ptys1", 0 },
+       { "/dev/ptys2", 0 },
+       { "/dev/ptys3", 0 },
+       { "/dev/ptys4", 0 },
+       { "/dev/ptys5", 0 },
+       { "/dev/ptys6", 0 },
+       { "/dev/ptys7", 0 },
+       { "/dev/ptys8", 0 },
+       { "/dev/ptys9", 0 },
+       { "/dev/ptysa", 0 },
+       { "/dev/ptysb", 0 },
+       { "/dev/ptysc", 0 },
+       { "/dev/ptysd", 0 },
+       { "/dev/ptyse", 0 },
+       { "/dev/ptysf", 0 },
+       { "/dev/ptyt0", 0 },
+       { "/dev/ptyt1", 0 },
+       { "/dev/ptyt2", 0 },
+       { "/dev/ptyt3", 0 },
+       { "/dev/ptyt4", 0 },
+       { "/dev/ptyt5", 0 },
+       { "/dev/ptyt6", 0 },
+       { "/dev/ptyt7", 0 },
+       { "/dev/ptyt8", 0 },
+       { "/dev/ptyt9", 0 },
+       { "/dev/ptyta", 0 },
+       { "/dev/ptytb", 0 },
+       { "/dev/ptytc", 0 },
+       { "/dev/ptytd", 0 },
+       { "/dev/ptyte", 0 },
+       { "/dev/ptytf", 0 },
+       { "/dev/ptyu0", 0 },
+       { "/dev/ptyu1", 0 },
+       { "/dev/ptyu2", 0 },
+       { "/dev/ptyu3", 0 },
+       { "/dev/ptyu4", 0 },
+       { "/dev/ptyu5", 0 },
+       { "/dev/ptyu6", 0 },
+       { "/dev/ptyu7", 0 },
+       { "/dev/ptyu8", 0 },
+       { "/dev/ptyu9", 0 },
+       { "/dev/ptyua", 0 },
+       { "/dev/ptyub", 0 },
+       { "/dev/ptyuc", 0 },
+       { "/dev/ptyud", 0 },
+       { "/dev/ptyue", 0 },
+       { "/dev/ptyuf", 0 },
+       { "/dev/ptyv0", 0 },
+       { "/dev/ptyv1", 0 },
+       { "/dev/ptyv2", 0 },
+       { "/dev/ptyv3", 0 },
+       { "/dev/ptyv4", 0 },
+       { "/dev/ptyv5", 0 },
+       { "/dev/ptyv6", 0 },
+       { "/dev/ptyv7", 0 },
+       { "/dev/ptyv8", 0 },
+       { "/dev/ptyv9", 0 },
+       { "/dev/ptyva", 0 },
+       { "/dev/ptyvb", 0 },
+       { "/dev/ptyvc", 0 },
+       { "/dev/ptyvd", 0 },
+       { "/dev/ptyve", 0 },
+       { "/dev/ptyvf", 0 },
+       { "/dev/ptyw0", 0 },
+       { "/dev/ptyw1", 0 },
+       { "/dev/ptyw2", 0 },
+       { "/dev/ptyw3", 0 },
+       { "/dev/ptyw4", 0 },
+       { "/dev/ptyw5", 0 },
+       { "/dev/ptyw6", 0 },
+       { "/dev/ptyw7", 0 },
+       { "/dev/ptyw8", 0 },
+       { "/dev/ptyw9", 0 },
+       { "/dev/ptywa", 0 },
+       { "/dev/ptywb", 0 },
+       { "/dev/ptywc", 0 },
+       { "/dev/ptywd", 0 },
+       { "/dev/ptywe", 0 },
+       { "/dev/ptywf", 0 },
+       { "/dev/ptyx0", 0 },
+       { "/dev/ptyx1", 0 },
+       { "/dev/ptyx2", 0 },
+       { "/dev/ptyx3", 0 },
+       { "/dev/ptyx4", 0 },
+       { "/dev/ptyx5", 0 },
+       { "/dev/ptyx6", 0 },
+       { "/dev/ptyx7", 0 },
+       { "/dev/ptyx8", 0 },
+       { "/dev/ptyx9", 0 },
+       { "/dev/ptyxa", 0 },
+       { "/dev/ptyxb", 0 },
+       { "/dev/ptyxc", 0 },
+       { "/dev/ptyxd", 0 },
+       { "/dev/ptyxe", 0 },
+       { "/dev/ptyxf", 0 },
+       { "/dev/ptyy0", 0 },
+       { "/dev/ptyy1", 0 },
+       { "/dev/ptyy2", 0 },
+       { "/dev/ptyy3", 0 },
+       { "/dev/ptyy4", 0 },
+       { "/dev/ptyy5", 0 },
+       { "/dev/ptyy6", 0 },
+       { "/dev/ptyy7", 0 },
+       { "/dev/ptyy8", 0 },
+       { "/dev/ptyy9", 0 },
+       { "/dev/ptyya", 0 },
+       { "/dev/ptyyb", 0 },
+       { "/dev/ptyyc", 0 },
+       { "/dev/ptyyd", 0 },
+       { "/dev/ptyye", 0 },
+       { "/dev/ptyyf", 0 },
+       { "/dev/ptyz0", 0 },
+       { "/dev/ptyz1", 0 },
+       { "/dev/ptyz2", 0 },
+       { "/dev/ptyz3", 0 },
+       { "/dev/ptyz4", 0 },
+       { "/dev/ptyz5", 0 },
+       { "/dev/ptyz6", 0 },
+       { "/dev/ptyz7", 0 },
+       { "/dev/ptyz8", 0 },
+       { "/dev/ptyz9", 0 },
+       { "/dev/ptyza", 0 },
+       { "/dev/ptyzb", 0 },
+       { "/dev/ptyzc", 0 },
+       { "/dev/ptyzd", 0 },
+       { "/dev/ptyze", 0 },
+       { "/dev/ptyzf", 0 },
+       { "/dev/ptya0", 0 },
+       { "/dev/ptya1", 0 },
+       { "/dev/ptya2", 0 },
+       { "/dev/ptya3", 0 },
+       { "/dev/ptya4", 0 },
+       { "/dev/ptya5", 0 },
+       { "/dev/ptya6", 0 },
+       { "/dev/ptya7", 0 },
+       { "/dev/ptya8", 0 },
+       { "/dev/ptya9", 0 },
+       { "/dev/ptyaa", 0 },
+       { "/dev/ptyab", 0 },
+       { "/dev/ptyac", 0 },
+       { "/dev/ptyad", 0 },
+       { "/dev/ptyae", 0 },
+       { "/dev/ptyaf", 0 },
+       { "/dev/ptyb0", 0 },
+       { "/dev/ptyb1", 0 },
+       { "/dev/ptyb2", 0 },
+       { "/dev/ptyb3", 0 },
+       { "/dev/ptyb4", 0 },
+       { "/dev/ptyb5", 0 },
+       { "/dev/ptyb6", 0 },
+       { "/dev/ptyb7", 0 },
+       { "/dev/ptyb8", 0 },
+       { "/dev/ptyb9", 0 },
+       { "/dev/ptyba", 0 },
+       { "/dev/ptybb", 0 },
+       { "/dev/ptybc", 0 },
+       { "/dev/ptybd", 0 },
+       { "/dev/ptybe", 0 },
+       { "/dev/ptybf", 0 },
+       { "/dev/ptyc0", 0 },
+       { "/dev/ptyc1", 0 },
+       { "/dev/ptyc2", 0 },
+       { "/dev/ptyc3", 0 },
+       { "/dev/ptyc4", 0 },
+       { "/dev/ptyc5", 0 },
+       { "/dev/ptyc6", 0 },
+       { "/dev/ptyc7", 0 },
+       { "/dev/ptyc8", 0 },
+       { "/dev/ptyc9", 0 },
+       { "/dev/ptyca", 0 },
+       { "/dev/ptycb", 0 },
+       { "/dev/ptycc", 0 },
+       { "/dev/ptycd", 0 },
+       { "/dev/ptyce", 0 },
+       { "/dev/ptycf", 0 },
+       { "/dev/ptyd0", 0 },
+       { "/dev/ptyd1", 0 },
+       { "/dev/ptyd2", 0 },
+       { "/dev/ptyd3", 0 },
+       { "/dev/ptyd4", 0 },
+       { "/dev/ptyd5", 0 },
+       { "/dev/ptyd6", 0 },
+       { "/dev/ptyd7", 0 },
+       { "/dev/ptyd8", 0 },
+       { "/dev/ptyd9", 0 },
+       { "/dev/ptyda", 0 },
+       { "/dev/ptydb", 0 },
+       { "/dev/ptydc", 0 },
+       { "/dev/ptydd", 0 },
+       { "/dev/ptyde", 0 },
+       { "/dev/ptydf", 0 },
+       { "/dev/ptye0", 0 },
+       { "/dev/ptye1", 0 },
+       { "/dev/ptye2", 0 },
+       { "/dev/ptye3", 0 },
+       { "/dev/ptye4", 0 },
+       { "/dev/ptye5", 0 },
+       { "/dev/ptye6", 0 },
+       { "/dev/ptye7", 0 },
+       { "/dev/ptye8", 0 },
+       { "/dev/ptye9", 0 },
+       { "/dev/ptyea", 0 },
+       { "/dev/ptyeb", 0 },
+       { "/dev/ptyec", 0 },
+       { "/dev/ptyed", 0 },
+       { "/dev/ptyee", 0 },
+       { "/dev/ptyef", 0 },
+       { "/dev/vcs", 0 },
+       { "/dev/vcsa", 0 },
+       { "/dev/vcs1", 0 },
+       { "/dev/vcsa1", 0 },
+       { "/dev/ttyS0", 0 },
+       { "/dev/cua0", 0 },
+       { "/dev/hda", 0 },
+       { "/dev/hda1", 2 },
+       { "/dev/hda2", 2 },
+       { "/dev/hda3", 2 },
+       { "/dev/hda4", 2 },
+       { "/dev/hda5", 2 },
+       { "/dev/hda6", 0 },
+       { "/dev/hda7", 0 },
+       { "/dev/hda8", 0 },
+       { "/dev/hdb", 0 },
+       { "/dev/hdb1", 2 },
+       { "/dev/hdc", 0 },
+       { "/dev/hdc1", 2 },
+       { "/dev/fd0u1440", 0 },
+       { "/dev/fd0u1680", 0 },
+       { "/dev/fd0u1722", 0 },
+       { "/dev/fd0u1743", 0 },
+       { "/dev/fd0u1760", 0 },
+       { "/dev/fd0u1920", 0 },
+       { "/dev/fd0u1840", 0 },
+       { "/dev/fd0u1600", 0 },
+       { "/dev/fd0u360", 0 },
+       { "/dev/fd0u720", 0 },
+       { "/dev/fd0u820", 0 },
+       { "/dev/fd0u830", 0 },
+       { "/dev/fd0u1040", 0 },
+       { "/dev/fd0u1120", 0 },
+       { "/dev/fd0u800", 0 },
+       { "/dev/fd0", 0 },
+       { "/dev/loop0", 0 },
+       { "/dev/loop1", 0 },
+       { "/dev/loop2", 0 },
+       { "/dev/loop3", 0 },
+       { "/dev/loop4", 0 },
+       { "/dev/loop5", 0 },
+       { "/dev/loop6", 0 },
+       { "/dev/loop7", 0 },
+       { "/dev/dsp", 0 },
+       { "/dev/dsp1", 0 },
+       { "/dev/mixer", 0 },
+       { "/dev/midi", 0 },
+       { "/dev/lvm", 0 },
+       { "/dev/vg0", 0 },
+       { "/dev/vg0/group", 0 },
+       { "/dev/vg0/packages", 0 },
+       { "/dev/vg0/photos", 0 },
+       { "/dev/vg0/music", 0 },
+       { "/dev/log", 0 },
+       { "/dev/MAKEDEV", 0 },
+       { "/dev/printer", 0 },
+       { "/dev/vcs2", 0 },
+       { "/dev/vcsa2", 0 },
+       { "/dev/vcs3", 0 },
+       { "/dev/vcsa3", 0 },
+       { "/dev/vcs5", 0 },
+       { "/dev/vcsa5", 0 },
+       { "/dev/vcs4", 0 },
+       { "/dev/vcsa4", 0 },
+       { "/dev/vcs6", 0 },
+       { "/dev/vcsa6", 0 },
+       { "/dev/nvidia0", 0 },
+       { "/dev/nvidia1", 0 },
+       { "/dev/nvidia2", 0 },
+       { "/dev/nvidia3", 0 },
+       { "/dev/nvidiactl", 0 },
+       { "/dev/vcs7", 0 },
+       { "/dev/vcsa7", 0 },
+       { NULL, 0 }
+};
diff --git a/test/unit/matcher_t.c b/test/unit/matcher_t.c
new file mode 100644 (file)
index 0000000..7331a82
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
+ * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * 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 "libdevmapper.h"
+#include "log.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <CUnit/CUnit.h>
+#include "matcher_data.h"
+
+int regex_init(void);
+int regex_fini(void);
+
+static struct dm_pool *mem = NULL;
+
+int regex_init(void) {
+       mem = dm_pool_create("bitset test", 1024);
+       return mem == NULL;
+}
+
+int regex_fini(void) {
+       dm_pool_destroy(mem);
+       return 0;
+}
+
+static struct dm_regex *make_scanner(const char **rx)
+{
+       struct dm_regex *scanner;
+       int nrx = 0;
+       for (; rx[nrx]; ++nrx);
+
+       scanner = dm_regex_create(mem, rx, nrx);
+       CU_ASSERT_FATAL(scanner != NULL);
+       return scanner;
+}
+
+static void test_fingerprints(void) {
+       struct dm_regex *scanner;
+
+       scanner = make_scanner(dev_patterns);
+       CU_ASSERT_EQUAL(dm_regex_fingerprint(scanner), 0x7f556c09);
+
+       scanner = make_scanner(random_patterns);
+       CU_ASSERT_EQUAL(dm_regex_fingerprint(scanner), 0x9f11076c);
+}
+
+static void test_matching(void) {
+       struct dm_regex *scanner;
+       int i;
+
+       scanner = make_scanner(dev_patterns);
+       for (i = 0; devices[i].str; ++i)
+               CU_ASSERT_EQUAL(dm_regex_match(scanner, devices[i].str), devices[i].expected - 1);
+
+       scanner = make_scanner(nonprint_patterns);
+       for (i = 0; nonprint[i].str; ++i)
+               CU_ASSERT_EQUAL(dm_regex_match(scanner, nonprint[i].str), nonprint[i].expected - 1);
+}
+
+CU_TestInfo regex_list[] = {
+       { (char*)"fingerprints", test_fingerprints },
+       { (char*)"matching", test_matching },
+       CU_TEST_INFO_NULL
+};
+
diff --git a/test/unit/run.c b/test/unit/run.c
new file mode 100644 (file)
index 0000000..482498a
--- /dev/null
@@ -0,0 +1,29 @@
+#include <CUnit/CUnit.h>
+#include <CUnit/Basic.h>
+
+#define DECL(n) \
+       extern CU_TestInfo n ## _list[]; \
+       int n ## _init(void); \
+       int n ## _fini(void);
+#define USE(n) { (char*) #n, n##_init, n##_fini, n##_list }
+
+DECL(bitset);
+DECL(regex);
+DECL(config);
+DECL(string);
+
+CU_SuiteInfo suites[] = {
+       USE(bitset),
+       USE(regex),
+       USE(config),
+       USE(string),
+       CU_SUITE_INFO_NULL
+};
+
+int main(int argc, char **argv) {
+       CU_initialize_registry();
+       CU_register_suites(suites);
+       CU_basic_set_mode(CU_BRM_VERBOSE);
+       CU_basic_run_tests();
+       return CU_get_number_of_failures() != 0;
+}
diff --git a/test/unit/string_t.c b/test/unit/string_t.c
new file mode 100644 (file)
index 0000000..df72505
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * 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 "libdevmapper.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <CUnit/CUnit.h>
+
+int string_init(void);
+int string_fini(void);
+
+static struct dm_pool *mem = NULL;
+
+int string_init(void)
+{
+       mem = dm_pool_create("string test", 1024);
+
+       return (mem == NULL);
+}
+
+int string_fini(void)
+{
+       dm_pool_destroy(mem);
+
+       return 0;
+}
+
+/* TODO: Add more string unit tests here */
+
+static void test_strncpy(void)
+{
+       const char st[] = "1234567890";
+       char buf[sizeof(st)];
+
+       CU_ASSERT_EQUAL(dm_strncpy(buf, st, sizeof(buf)), 1);
+       CU_ASSERT_EQUAL(strcmp(buf, st), 0);
+
+       CU_ASSERT_EQUAL(dm_strncpy(buf, st, sizeof(buf) - 1), 0);
+       CU_ASSERT_EQUAL(strlen(buf) + 1, sizeof(buf) - 1);
+}
+
+static void test_asprint(void)
+{
+       const char st0[] = "";
+       const char st1[] = "12345678901";
+       const char st2[] = "1234567890123456789012345678901234567890123456789012345678901234567";
+       char *buf;
+       int a;
+
+       a = dm_asprintf(&buf, "%s", st0);
+       CU_ASSERT_EQUAL(strcmp(buf, st0), 0);
+       CU_ASSERT_EQUAL(a, sizeof(st0));
+       free(buf);
+
+       a = dm_asprintf(&buf, "%s", st1);
+       CU_ASSERT_EQUAL(strcmp(buf, st1), 0);
+       CU_ASSERT_EQUAL(a, sizeof(st1));
+       free(buf);
+
+       a = dm_asprintf(&buf, "%s", st2);
+       CU_ASSERT_EQUAL(a, sizeof(st2));
+       CU_ASSERT_EQUAL(strcmp(buf, st2), 0);
+       free(buf);
+}
+
+CU_TestInfo string_list[] = {
+       { (char*)"asprint", test_asprint },
+       { (char*)"strncpy", test_strncpy },
+       CU_TEST_INFO_NULL
+};
index 70a1b61eedbbc646b610cb676b1f035224017fbe..15843f0e125265620cfd5a7438fa598c1ebed528 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
-# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
 #
 # This file is part of LVM2.
 #
@@ -132,7 +132,7 @@ dmsetup.static: dmsetup.o $(interfacebuilddir)/libdevmapper.a
 all: device-mapper
 
 lvm: $(OBJECTS) lvm.o $(top_builddir)/lib/liblvm-internal.a
-       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) lvm.o \
+       $(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -o $@ $(OBJECTS) lvm.o \
                $(LVMLIBS) $(READLINE_LIBS) $(LIBS) -rdynamic
 
 lvm.static: $(OBJECTS) lvm-static.o $(top_builddir)/lib/liblvm-internal.a  $(interfacebuilddir)/libdevmapper.a
@@ -203,5 +203,3 @@ install_device-mapper: $(INSTALL_DMSETUP_TARGETS)
 install_lvm2: $(INSTALL_LVM_TARGETS)
 
 install: install_lvm2 install_device-mapper
-
-DISTCLEAN_TARGETS += .exported_symbols_generated
index ff7514b4fc886b96ece2d4007b752e23e7a97add..0d9605a8911aa972c213981392da661543b37397 100644 (file)
@@ -18,7 +18,6 @@
  */
 /* *INDENT-OFF* */
 arg(version_ARG, '\0', "version", NULL, 0)
-arg(quiet_ARG, '\0', "quiet", NULL, 0)
 arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", size_mb_arg, 0)
 arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", NULL, 0)
 arg(nolocking_ARG, '\0', "nolocking", NULL, 0)
@@ -44,7 +43,7 @@ arg(addtag_ARG, '\0', "addtag", tag_arg, ARG_GROUPABLE)
 arg(deltag_ARG, '\0', "deltag", tag_arg, ARG_GROUPABLE)
 arg(refresh_ARG, '\0', "refresh", NULL, 0)
 arg(mknodes_ARG, '\0', "mknodes", NULL, 0)
-arg(minor_ARG, '\0', "minor", minor_arg, 0)
+arg(minor_ARG, '\0', "minor", int_arg, ARG_GROUPABLE)
 arg(type_ARG, '\0', "type", segtype_arg, 0)
 arg(alloc_ARG, '\0', "alloc", alloc_arg, 0)
 arg(separator_ARG, '\0', "separator", string_arg, 0)
@@ -54,11 +53,14 @@ arg(resync_ARG, '\0', "resync", NULL, 0)
 arg(corelog_ARG, '\0', "corelog", NULL, 0)
 arg(mirrorlog_ARG, '\0', "mirrorlog", string_arg, 0)
 arg(splitmirrors_ARG, '\0', "splitmirrors", int_arg, 0)
+arg(trackchanges_ARG, '\0', "trackchanges", NULL, 0)
+arg(replace_ARG, '\0', "replace", string_arg, ARG_GROUPABLE)
 arg(repair_ARG, '\0', "repair", NULL, 0)
 arg(use_policies_ARG, '\0', "use-policies", NULL, 0)
 arg(monitor_ARG, '\0', "monitor", yes_no_arg, 0)
 arg(config_ARG, '\0', "config", string_arg, 0)
 arg(trustcache_ARG, '\0', "trustcache", NULL, 0)
+arg(cache_ARG, '\0', "cache", NULL, 0)
 arg(ignoremonitoring_ARG, '\0', "ignoremonitoring", NULL, 0)
 arg(nameprefixes_ARG, '\0', "nameprefixes", NULL, 0)
 arg(unquoted_ARG, '\0', "unquoted", NULL, 0)
@@ -66,20 +68,24 @@ arg(rows_ARG, '\0', "rows", NULL, 0)
 arg(dataalignment_ARG, '\0', "dataalignment", size_kb_arg, 0)
 arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", size_kb_arg, 0)
 arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", size_mb_arg, 0)
-arg(virtualsize_ARG, '\0', "virtualsize", size_mb_arg, 0)
 arg(noudevsync_ARG, '\0', "noudevsync", NULL, 0)
 arg(poll_ARG, '\0', "poll", yes_no_arg, 0)
+arg(poolmetadata_ARG, '\0', "poolmetadata", string_arg, 0)
+arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", size_mb_arg, 0)
+arg(discards_ARG, '\0', "discards", discards_arg, 0)
 arg(stripes_long_ARG, '\0', "stripes", int_arg, 0)
 arg(sysinit_ARG, '\0', "sysinit", NULL, 0)
+arg(thinpool_ARG, '\0', "thinpool", string_arg, 0)
 
 /* Allow some variations */
 arg(resizable_ARG, '\0', "resizable", yes_no_arg, 0)
 arg(allocation_ARG, '\0', "allocation", yes_no_arg, 0)
+arg(available_ARG, '\0', "available", activation_arg, 0)
 
 /*
  * ... and now the short args.
  */
-arg(available_ARG, 'a', "available", yes_no_excl_arg, 0)
+arg(activate_ARG, 'a', "activate", activation_arg, 0)
 arg(all_ARG, 'a', "all", NULL, 0)
 arg(autobackup_ARG, 'A', "autobackup", yes_no_arg, 0)
 arg(activevolumegroups_ARG, 'A', "activevolumegroups", NULL, 0)
@@ -111,7 +117,7 @@ arg(size_ARG, 'L', "size", size_mb_arg, 0)
 arg(logicalextent_ARG, 'L', "logicalextent", int_arg_with_sign, 0)
 arg(persistent_ARG, 'M', "persistent", yes_no_arg, 0)
 arg(merge_ARG, '\0', "merge", NULL, 0)
-arg(major_ARG, 'j', "major", major_arg, 0)
+arg(major_ARG, 'j', "major", int_arg, ARG_GROUPABLE)
 arg(mirrors_ARG, 'm', "mirrors", int_arg_with_sign, 0)
 arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_arg, 0)
 arg(maps_ARG, 'm', "maps", NULL, 0)
@@ -125,6 +131,7 @@ arg(permission_ARG, 'p', "permission", permission_arg, 0)
 arg(maxphysicalvolumes_ARG, 'p', "maxphysicalvolumes", int_arg, 0)
 arg(partial_ARG, 'P', "partial", NULL, 0)
 arg(physicalvolume_ARG, 'P', "physicalvolume", NULL, 0)
+arg(quiet_ARG, 'q', "quiet", NULL, ARG_COUNTABLE)
 arg(readahead_ARG, 'r', "readahead", readahead_arg, 0)
 arg(resizefs_ARG, 'r', "resizefs", NULL, 0)
 arg(reset_ARG, 'R', "reset", NULL, 0)
@@ -133,12 +140,14 @@ arg(physicalextentsize_ARG, 's', "physicalextentsize", size_mb_arg, 0)
 arg(stdin_ARG, 's', "stdin", NULL, 0)
 arg(snapshot_ARG, 's', "snapshot", NULL, 0)
 arg(short_ARG, 's', "short", NULL, 0)
+arg(thin_ARG, 'T', "thin", NULL, 0)
 arg(test_ARG, 't', "test", NULL, 0)
 arg(uuid_ARG, 'u', "uuid", NULL, 0)
 arg(uuidstr_ARG, 'u', "uuid", string_arg, 0)
 arg(uuidlist_ARG, 'U', "uuidlist", NULL, 0)
 arg(verbose_ARG, 'v', "verbose", NULL, ARG_COUNTABLE)
 arg(volumegroup_ARG, 'V', "volumegroup", NULL, 0)
+arg(virtualsize_ARG, 'V', "virtualsize", size_mb_arg, 0)
 arg(allocatable_ARG, 'x', "allocatable", yes_no_arg, 0)
 arg(resizeable_ARG, 'x', "resizeable", yes_no_arg, 0)
 arg(yes_ARG, 'y', "yes", NULL, 0)
index fa177cd394932f697ac68a82a3414a32c5651050..6415d34b838a413ab721e55fa56b3438eb9e60d5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -61,7 +61,7 @@ xx(lvchange,
    CACHE_VGMETADATA | PERMITTED_READ_ONLY,
    "lvchange\n"
    "\t[-A|--autobackup y|n]\n"
-   "\t[-a|--available [e|l]y|n]\n"
+   "\t[-a|--activate [a|e|l]{y|n}]\n"
    "\t[--addtag Tag]\n"
    "\t[--alloc AllocationPolicy]\n"
    "\t[-C|--contiguous y|n]\n"
@@ -69,6 +69,7 @@ xx(lvchange,
    "\t[--deltag Tag]\n"
    "\t[-f|--force]\n"
    "\t[-h|--help]\n"
+   "\t[--discards {ignore|nopassdown|passdown}]\n"
    "\t[--ignorelockingfailure]\n"
    "\t[--ignoremonitoring]\n"
    "\t[--monitor {y|n}]\n"
@@ -84,21 +85,25 @@ xx(lvchange,
    "\t[-t|--test]\n"
    "\t[-v|--verbose]\n"
    "\t[-y|--yes]\n"
-   "\t[--version]" "\n"
+   "\t[--version]\n"
+   "\t[-Z|--zero {y|n}]\n"
    "\tLogicalVolume[Path] [LogicalVolume[Path]...]\n",
 
-   alloc_ARG, autobackup_ARG, available_ARG, contiguous_ARG, force_ARG,
-   ignorelockingfailure_ARG, ignoremonitoring_ARG, major_ARG, minor_ARG,
-   monitor_ARG, noudevsync_ARG, partial_ARG, permission_ARG, persistent_ARG,
-   poll_ARG, readahead_ARG, resync_ARG, refresh_ARG, addtag_ARG, deltag_ARG,
-   sysinit_ARG, test_ARG, yes_ARG)
+   alloc_ARG, autobackup_ARG, activate_ARG, available_ARG, contiguous_ARG,
+   discards_ARG, force_ARG, ignorelockingfailure_ARG, ignoremonitoring_ARG,
+   major_ARG, minor_ARG, monitor_ARG, noudevsync_ARG, partial_ARG,
+   permission_ARG, persistent_ARG, poll_ARG, readahead_ARG, resync_ARG,
+   refresh_ARG, addtag_ARG, deltag_ARG, sysinit_ARG, test_ARG, yes_ARG,
+   zero_ARG)
 
 xx(lvconvert,
    "Change logical volume layout",
    0,
    "lvconvert "
    "[-m|--mirrors Mirrors [{--mirrorlog {disk|core|mirrored}|--corelog}]]\n"
+   "\t[--type SegmentType]\n"
    "\t[--repair [--use-policies]]\n"
+   "\t[--replace PhysicalVolume]\n"
    "\t[-R|--regionsize MirrorLogRegionSize]\n"
    "\t[--alloc AllocationPolicy]\n"
    "\t[-b|--background]\n"
@@ -114,6 +119,7 @@ xx(lvconvert,
    "\tLogicalVolume[Path] [PhysicalVolume[Path]...]\n\n"
 
    "lvconvert "
+   "[--splitmirrors Images --trackchanges]\n"
    "[--splitmirrors Images --name SplitLogicalVolumeName]\n"
    "\tLogicalVolume[Path] [SplittablePhysicalVolume[Path]...]\n\n"
 
@@ -135,12 +141,21 @@ xx(lvconvert,
    "\t[-d|--debug]\n"
    "\t[-h|-?|--help]\n"
    "\t[-v|--verbose]\n"
-   "\tSnapshotLogicalVolume[Path]\n",
+   "\tLogicalVolume[Path]\n\n"
+
+   "lvconvert "
+   "--thinpool ThinPoolLogicalVolume[Path]\n"
+   "\t[--chunksize size]\n"
+   "\t[--discards {ignore|nopassdown|passdown}]\n"
+   "\t[[--poolmetadatasize size] | --poolmetadata ThinMetadataLogicalVolume[Path]]\n"
+   "\t[-Z|--zero {y|n}]\n"
+   "\t[-d|--debug] [-h|-?|--help] [-v|--verbose]\n",
 
    alloc_ARG, background_ARG, chunksize_ARG, corelog_ARG, interval_ARG,
    merge_ARG, mirrorlog_ARG, mirrors_ARG, name_ARG, noudevsync_ARG,
-   regionsize_ARG, repair_ARG, snapshot_ARG, splitmirrors_ARG,
-   stripes_long_ARG, stripesize_ARG, test_ARG,
+   regionsize_ARG, repair_ARG, replace_ARG, snapshot_ARG, splitmirrors_ARG,
+   trackchanges_ARG, type_ARG, stripes_long_ARG, stripesize_ARG, test_ARG,
+   chunksize_ARG, discards_ARG, poolmetadata_ARG, poolmetadatasize_ARG, thinpool_ARG,
    use_policies_ARG, yes_ARG, force_ARG, zero_ARG)
 
 xx(lvcreate,
@@ -148,6 +163,7 @@ xx(lvcreate,
    0,
    "lvcreate " "\n"
    "\t[-A|--autobackup {y|n}]\n"
+   "\t[-a|--activate [a|e|l]{y|n}]\n"
    "\t[--addtag Tag]\n"
    "\t[--alloc AllocationPolicy]\n"
    "\t[-C|--contiguous {y|n}]\n"
@@ -165,6 +181,10 @@ xx(lvcreate,
    "\t[-p|--permission {r|rw}]\n"
    "\t[-r|--readahead ReadAheadSectors|auto|none]\n"
    "\t[-R|--regionsize MirrorLogRegionSize]\n"
+   "\t[-T|--thin  [-c|--chunksize  ChunkSize]\n"
+   "\t  [--discards {ignore|nopassdown|passdown}]\n"
+   "\t  [--poolmetadatasize MetadataSize[bBsSkKmMgG]]]\n"
+   "\t[--thinpool ThinPoolLogicalVolume{Name|Path}]\n"
    "\t[-t|--test]\n"
    "\t[--type VolumeType]\n"
    "\t[-v|--verbose]\n"
@@ -174,36 +194,42 @@ xx(lvcreate,
 
    "lvcreate \n"
    "\t{ {-s|--snapshot} OriginalLogicalVolume[Path] |\n"
-   "\t  [-s|--snapshot] VolumeGroupName[Path] --virtualsize VirtualSize}\n"
+   "\t  [-s|--snapshot] VolumeGroupName[Path] -V|--virtualsize VirtualSize}\n"
+   "\t  {-T|--thin} VolumeGroupName[Path][/PoolLogicalVolume] \n"
+   "\t              -V|--virtualsize VirtualSize}\n"
    "\t[-c|--chunksize]\n"
    "\t[-A|--autobackup {y|n}]\n"
    "\t[--addtag Tag]\n"
    "\t[--alloc AllocationPolicy]\n"
    "\t[-C|--contiguous {y|n}]\n"
    "\t[-d|--debug]\n"
+   "\t[--discards {ignore|nopassdown|passdown}]\n"
    "\t[-h|-?|--help]\n"
    "\t[--ignoremonitoring]\n"
    "\t[--monitor {y|n}]\n"
    "\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
    "\t{-l|--extents LogicalExtentsNumber[%{VG|FREE|ORIGIN}] |\n"
    "\t -L|--size LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n"
+   "\t[--poolmetadatasize Size[bBsSkKmMgG]]\n"
    "\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n"
    "\t[-n|--name LogicalVolumeName]\n"
    "\t[--noudevsync]\n"
    "\t[-p|--permission {r|rw}]\n"
    "\t[-r|--readahead ReadAheadSectors|auto|none]\n"
    "\t[-t|--test]\n"
+   "\t[--thinpool ThinPoolLogicalVolume[Path]]\n"
    "\t[-v|--verbose]\n"
    "\t[--version]\n"
 
    "\t[PhysicalVolumePath...]\n\n",
 
-   addtag_ARG, alloc_ARG, autobackup_ARG, chunksize_ARG, contiguous_ARG,
-   corelog_ARG, extents_ARG, ignoremonitoring_ARG, major_ARG, minor_ARG,
-   mirrorlog_ARG, mirrors_ARG, monitor_ARG, name_ARG, nosync_ARG, noudevsync_ARG,
-   permission_ARG, persistent_ARG, readahead_ARG, regionsize_ARG, size_ARG,
-   snapshot_ARG, stripes_ARG, stripesize_ARG, test_ARG, type_ARG,
-   virtualoriginsize_ARG, virtualsize_ARG, zero_ARG)
+   addtag_ARG, alloc_ARG, autobackup_ARG, activate_ARG, available_ARG,
+   chunksize_ARG, contiguous_ARG, corelog_ARG, discards_ARG, extents_ARG,
+   ignoremonitoring_ARG, major_ARG, minor_ARG, mirrorlog_ARG, mirrors_ARG,
+   monitor_ARG, name_ARG, nosync_ARG, noudevsync_ARG, permission_ARG,
+   persistent_ARG, readahead_ARG, regionsize_ARG, size_ARG, snapshot_ARG,
+   stripes_ARG, stripesize_ARG, test_ARG, thin_ARG, thinpool_ARG, type_ARG,
+   virtualoriginsize_ARG, poolmetadatasize_ARG, virtualsize_ARG, zero_ARG)
 
 xx(lvdisplay,
    "Display information about a logical volume",
@@ -259,6 +285,7 @@ xx(lvextend,
    "\t{-l|--extents [+]LogicalExtentsNumber[%{VG|LV|PVS|FREE|ORIGIN}] |\n"
    "\t -L|--size [+]LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n"
    "\t[-m|--mirrors Mirrors]\n"
+   "\t[--nosync]\n"
    "\t[--use-policies]\n"
    "\t[-n|--nofsck]\n"
    "\t[--noudevsync]\n"
@@ -270,7 +297,7 @@ xx(lvextend,
    "\tLogicalVolume[Path] [ PhysicalVolumePath... ]\n",
 
    alloc_ARG, autobackup_ARG, extents_ARG, force_ARG, mirrors_ARG,
-   nofsck_ARG, noudevsync_ARG, resizefs_ARG, size_ARG, stripes_ARG,
+   nofsck_ARG, nosync_ARG, noudevsync_ARG, resizefs_ARG, size_ARG, stripes_ARG,
    stripesize_ARG, test_ARG, type_ARG, use_policies_ARG)
 
 xx(lvmchange,
@@ -361,7 +388,7 @@ xx(lvremove,
 xx(lvrename,
    "Rename a logical volume",
    0,
-   "lvrename "
+   "lvrename\n"
    "\t[-A|--autobackup {y|n}] " "\n"
    "\t[-d|--debug] " "\n"
    "\t[-h|-?|--help] " "\n"
@@ -653,6 +680,8 @@ xx(pvscan,
    "List all physical volumes",
    PERMITTED_READ_ONLY,
    "pvscan " "\n"
+   "\t[-a|--activate ay]\n"
+   "\t[--cache [ DevicePath | --major major --minor minor]...]\n"
    "\t[-d|--debug] " "\n"
    "\t{-e|--exported | -n|--novolumegroup} " "\n"
    "\t[-h|-?|--help]" "\n"
@@ -663,8 +692,9 @@ xx(pvscan,
    "\t[-v|--verbose] " "\n"
    "\t[--version]\n",
 
-   exported_ARG, ignorelockingfailure_ARG, novolumegroup_ARG, partial_ARG,
-   short_ARG, uuid_ARG)
+   activate_ARG, available_ARG, cache_ARG, exported_ARG,
+   ignorelockingfailure_ARG, major_ARG, minor_ARG,
+   novolumegroup_ARG, partial_ARG, short_ARG, uuid_ARG)
 
 xx(segtypes,
    "List available segment types",
@@ -723,7 +753,7 @@ xx(vgchange,
    "\t[-u|--uuid] " "\n"
    "\t[-v|--verbose] " "\n"
    "\t[--version]" "\n"
-   "\t{-a|--available [e|l]{y|n}  |" "\n"
+   "\t{-a|--activate [a|e|l]{y|n}  |" "\n"
    "\t -c|--clustered {y|n} |" "\n"
    "\t -x|--resizeable {y|n} |" "\n"
    "\t -l|--logicalvolume MaxLogicalVolumes |" "\n"
@@ -733,11 +763,11 @@ xx(vgchange,
    "\t --deltag Tag}\n"
    "\t[VolumeGroupName...]\n",
 
-   addtag_ARG, alloc_ARG, allocation_ARG, autobackup_ARG, available_ARG,
-   clustered_ARG, deltag_ARG, ignorelockingfailure_ARG, ignoremonitoring_ARG,
-   logicalvolume_ARG, maxphysicalvolumes_ARG, monitor_ARG, noudevsync_ARG,
-   metadatacopies_ARG, vgmetadatacopies_ARG, partial_ARG,
-   physicalextentsize_ARG, poll_ARG, refresh_ARG, resizeable_ARG,
+   addtag_ARG, alloc_ARG, allocation_ARG, autobackup_ARG, activate_ARG,
+   available_ARG, clustered_ARG, deltag_ARG, ignorelockingfailure_ARG,
+   ignoremonitoring_ARG, logicalvolume_ARG, maxphysicalvolumes_ARG,
+   monitor_ARG, noudevsync_ARG, metadatacopies_ARG, vgmetadatacopies_ARG,
+   partial_ARG, physicalextentsize_ARG, poll_ARG, refresh_ARG, resizeable_ARG,
    resizable_ARG, sysinit_ARG, test_ARG, uuid_ARG)
 
 xx(vgck,
@@ -993,6 +1023,7 @@ xx(vgscan,
    "Search for all volume groups",
    PERMITTED_READ_ONLY,
    "vgscan "
+   "\t[--cache]\n"
    "\t[-d|--debug]\n"
    "\t[-h|--help]\n"
    "\t[--ignorelockingfailure]\n"
@@ -1001,7 +1032,7 @@ xx(vgscan,
    "\t[-v|--verbose]\n"
    "\t[--version]" "\n",
 
-   ignorelockingfailure_ARG, mknodes_ARG, partial_ARG)
+   cache_ARG, ignorelockingfailure_ARG, mknodes_ARG, partial_ARG)
 
 xx(vgsplit,
    "Move physical volumes into a new or existing volume group",
index 2eeee7fd938464464acf4b9716454813513ee1a0..196c1700d11688fd66f6a6e361677e5d12d42fad 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  * Copyright (C) 2005-2007 NEC Corporation
  *
  * This file is part of the device-mapper userspace tools.
@@ -30,7 +30,6 @@
 #include <dirent.h>
 #include <errno.h>
 #include <unistd.h>
-#include <libgen.h>
 #include <sys/wait.h>
 #include <unistd.h>
 #include <sys/param.h>
@@ -45,7 +44,6 @@
 #  include <sys/types.h>
 #  include <sys/ipc.h>
 #  include <sys/sem.h>
-#  define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
 #  include <libudev.h>
 #endif
 
@@ -118,12 +116,16 @@ extern char *optarg;
  */
 enum {
        READ_ONLY = 0,
+       ADD_NODE_ON_CREATE_ARG,
+       ADD_NODE_ON_RESUME_ARG,
+       CHECKS_ARG,
        COLS_ARG,
        EXEC_ARG,
        FORCE_ARG,
        GID_ARG,
        HELP_ARG,
        INACTIVE_ARG,
+       MANGLENAME_ARG,
        MAJOR_ARG,
        MINOR_ARG,
        MODE_ARG,
@@ -138,6 +140,7 @@ enum {
        NOUDEVSYNC_ARG,
        OPTIONS_ARG,
        READAHEAD_ARG,
+       RETRY_ARG,
        ROWS_ARG,
        SEPARATOR_ARG,
        SETUUID_ARG,
@@ -151,6 +154,7 @@ enum {
        UNQUOTED_ARG,
        UUID_ARG,
        VERBOSE_ARG,
+       VERIFYUDEV_ARG,
        VERSION_ARG,
        YES_ARG,
        NUM_SWITCHES
@@ -164,6 +168,12 @@ typedef enum {
        DR_NAME = 16
 } report_type_t;
 
+typedef enum {
+       DN_DEVNO,       /* Major and minor number pair */
+       DN_BLK,         /* Block device name (e.g. dm-0) */
+       DN_MAP          /* Map name (for dm devices only, equal to DN_BLK otherwise) */
+} dev_name_t;
+
 static int _switches[NUM_SWITCHES];
 static int _int_args[NUM_SWITCHES];
 static char *_string_args[NUM_SWITCHES];
@@ -178,18 +188,22 @@ static int _udev_only;
 static struct dm_tree *_dtree;
 static struct dm_report *_report;
 static report_type_t _report_type;
+static dev_name_t _dev_name_type;
 
 /*
  * Commands
  */
 
-typedef int (*command_fn) (int argc, char **argv, void *data);
+struct command;
+#define CMD_ARGS const struct command *cmd, int argc, char **argv, struct dm_names *names, int multiple_devices
+typedef int (*command_fn) (CMD_ARGS);
 
 struct command {
        const char *name;
        const char *help;
        int min_args;
        int max_args;
+       int repeatable_cmd;     /* Repeat to process device list? */
        command_fn fn;
 };
 
@@ -312,6 +326,9 @@ static struct dm_task *_get_deps_task(int major, int minor)
        if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
                goto err;
 
+       if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+               goto err;
+
        if (!dm_task_run(dmt))
                goto err;
 
@@ -362,7 +379,11 @@ static struct dm_split_name *_get_split_name(const char *uuid, const char *name,
                return NULL;
        }
 
-       split_name->subsystem = _extract_uuid_prefix(uuid, separator);
+       if (!(split_name->subsystem = _extract_uuid_prefix(uuid, separator))) {
+               dm_free(split_name);
+               return_NULL;
+       }
+
        split_name->vg_name = split_name->lv_name =
            split_name->lv_layer = (char *) "";
 
@@ -405,16 +426,24 @@ static int _display_info_cols(struct dm_task *dmt, struct dm_info *info)
        obj.split_name = NULL;
 
        if (_report_type & DR_TREE)
-               obj.tree_node = dm_tree_find_node(_dtree, info->major, info->minor);
+               if (!(obj.tree_node = dm_tree_find_node(_dtree, info->major, info->minor))) {
+                       log_error("Cannot find node %d:%d.", info->major, info->minor);
+                       goto out;
+               }
 
        if (_report_type & DR_DEPS)
-               obj.deps_task = _get_deps_task(info->major, info->minor);
+               if (!(obj.deps_task = _get_deps_task(info->major, info->minor))) {
+                       log_error("Cannot get deps for %d:%d.", info->major, info->minor);
+                       goto out;
+               }
 
        if (_report_type & DR_NAME)
-               obj.split_name = _get_split_name(dm_task_get_uuid(dmt), dm_task_get_name(dmt), '-');
+               if (!(obj.split_name = _get_split_name(dm_task_get_uuid(dmt),
+                                                      dm_task_get_name(dmt), '-')))
+                       goto_out;
 
        if (!dm_report_object(_report, &obj))
-               goto out;
+               goto_out;
 
        r = 1;
 
@@ -505,7 +534,23 @@ static int _set_task_device(struct dm_task *dmt, const char *name, int optional)
        return 1;
 }
 
-static int _load(int argc, char **argv, void *data __attribute__((unused)))
+static int _set_task_add_node(struct dm_task *dmt)
+{
+       if (!dm_task_set_add_node(dmt, DEFAULT_DM_ADD_NODE))
+               return 0;
+
+       if (_switches[ADD_NODE_ON_RESUME_ARG] &&
+           !dm_task_set_add_node(dmt, DM_ADD_NODE_ON_RESUME))
+               return 0;
+
+       if (_switches[ADD_NODE_ON_CREATE_ARG] &&
+           !dm_task_set_add_node(dmt, DM_ADD_NODE_ON_CREATE))
+               return 0;
+
+       return 1;
+}
+
+static int _load(CMD_ARGS)
 {
        int r = 0;
        struct dm_task *dmt;
@@ -551,6 +596,9 @@ static int _load(int argc, char **argv, void *data __attribute__((unused)))
        if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
                goto out;
 
+       if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+               goto out;
+
        if (!dm_task_run(dmt))
                goto out;
 
@@ -565,7 +613,7 @@ static int _load(int argc, char **argv, void *data __attribute__((unused)))
        return r;
 }
 
-static int _create(int argc, char **argv, void *data __attribute__((unused)))
+static int _create(CMD_ARGS)
 {
        int r = 0;
        struct dm_task *dmt;
@@ -624,11 +672,17 @@ static int _create(int argc, char **argv, void *data __attribute__((unused)))
                udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG |
                              DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
 
-       if (_udev_cookie) {
+       if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+               goto out;
+
+       if (!_set_task_add_node(dmt))
+                goto out;
+
+       if (_udev_cookie)
                cookie = _udev_cookie;
-               if (_udev_only)
-                       udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
-       }
+
+       if (_udev_only)
+               udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
 
        if (!dm_task_set_cookie(dmt, &cookie, udev_flags) ||
            !dm_task_run(dmt))
@@ -636,26 +690,19 @@ static int _create(int argc, char **argv, void *data __attribute__((unused)))
 
        r = 1;
 
+      out:
        if (!_udev_cookie)
                (void) dm_udev_wait(cookie);
 
-       if (_switches[VERBOSE_ARG])
+       if (r && _switches[VERBOSE_ARG])
                r = _display_info(dmt);
 
        dm_task_destroy(dmt);
 
-       return r;
-
-      out:
-       if (!_udev_cookie)
-               (void) dm_udev_wait(cookie);
-       dm_task_destroy(dmt);
-
        return r;
 }
 
-static int _rename(int argc, char **argv, void *data __attribute__((unused)))
-{
+static int _do_rename(const char *name, const char *new_name, const char *new_uuid) {
        int r = 0;
        struct dm_task *dmt;
        uint32_t cookie = 0;
@@ -665,13 +712,13 @@ static int _rename(int argc, char **argv, void *data __attribute__((unused)))
                return 0;
 
        /* FIXME Kernel doesn't support uuid or device number here yet */
-       if (!_set_task_device(dmt, (argc == 3) ? argv[1] : NULL, 0))
+       if (!_set_task_device(dmt, name, 0))
                goto out;
 
-       if (_switches[SETUUID_ARG]) {
-               if  (!dm_task_set_newuuid(dmt, argv[argc - 1]))
+       if (new_uuid) {
+               if (!dm_task_set_newuuid(dmt, new_uuid))
                        goto out;
-       } else if (!dm_task_set_newname(dmt, argv[argc - 1]))
+       } else if (!new_name || !dm_task_set_newname(dmt, new_name))
                goto out;
 
        if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
@@ -680,15 +727,18 @@ static int _rename(int argc, char **argv, void *data __attribute__((unused)))
        if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
                goto out;
 
+       if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+               goto out;
+
        if (_switches[NOUDEVRULES_ARG])
                udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG |
                              DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
 
-       if (_udev_cookie) {
+       if (_udev_cookie)
                cookie = _udev_cookie;
-               if (_udev_only)
-                       udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
-       }
+
+       if (_udev_only)
+               udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
 
        if (!dm_task_set_cookie(dmt, &cookie, udev_flags) ||
            !dm_task_run(dmt))
@@ -699,12 +749,22 @@ static int _rename(int argc, char **argv, void *data __attribute__((unused)))
       out:
        if (!_udev_cookie)
                (void) dm_udev_wait(cookie);
+
        dm_task_destroy(dmt);
 
        return r;
 }
 
-static int _message(int argc, char **argv, void *data __attribute__((unused)))
+static int _rename(CMD_ARGS)
+{
+       const char *name = (argc == 3) ? argv[1] : NULL;
+
+       return _switches[SETUUID_ARG] ? _do_rename(name, NULL, argv[argc - 1]) :
+                                       _do_rename(name, argv[argc - 1], NULL);
+
+}
+
+static int _message(CMD_ARGS)
 {
        int r = 0, i;
        size_t sz = 1;
@@ -747,17 +807,22 @@ static int _message(int argc, char **argv, void *data __attribute__((unused)))
                strcat(str, argv[i]);
        }
 
-       if (!dm_task_set_message(dmt, str))
-               goto out;
+       i = dm_task_set_message(dmt, str);
 
        dm_free(str);
 
+       if (!i)
+               goto out;
+
        if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
                goto out;
 
        if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
                goto out;
 
+       if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+               goto out;
+
        if (!dm_task_run(dmt))
                goto out;
 
@@ -769,7 +834,7 @@ static int _message(int argc, char **argv, void *data __attribute__((unused)))
        return r;
 }
 
-static int _setgeometry(int argc, char **argv, void *data __attribute__((unused)))
+static int _setgeometry(CMD_ARGS)
 {
        int r = 0;
        struct dm_task *dmt;
@@ -796,6 +861,9 @@ static int _setgeometry(int argc, char **argv, void *data __attribute__((unused)
        if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
                goto out;
 
+       if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+               goto out;
+
        /* run the task */
        if (!dm_task_run(dmt))
                goto out;
@@ -808,7 +876,7 @@ static int _setgeometry(int argc, char **argv, void *data __attribute__((unused)
        return r;
 }
 
-static int _splitname(int argc, char **argv, void *data __attribute__((unused)))
+static int _splitname(CMD_ARGS)
 {
        struct dmsetup_report_obj obj;
        int r = 1;
@@ -817,8 +885,9 @@ static int _splitname(int argc, char **argv, void *data __attribute__((unused)))
        obj.info = NULL;
        obj.deps_task = NULL;
        obj.tree_node = NULL;
-       obj.split_name = _get_split_name((argc == 3) ? argv[2] : "LVM",
-                                        argv[1], '\0');
+       if (!(obj.split_name = _get_split_name((argc == 3) ? argv[2] : "LVM",
+                                              argv[1], '\0')))
+                return_0;
 
        r = dm_report_object(_report, &obj);
        _destroy_split_name(obj.split_name);
@@ -842,7 +911,7 @@ static uint32_t _get_cookie_value(const char *str_value)
                return (uint32_t) value;
 }
 
-static int _udevflags(int args, char **argv, void *data __attribute__((unused)))
+static int _udevflags(CMD_ARGS)
 {
        uint32_t cookie;
        uint16_t flags;
@@ -884,7 +953,7 @@ static int _udevflags(int args, char **argv, void *data __attribute__((unused)))
        return 1;
 }
 
-static int _udevcomplete(int argc, char **argv, void *data __attribute__((unused)))
+static int _udevcomplete(CMD_ARGS)
 {
        uint32_t cookie;
 
@@ -907,32 +976,30 @@ static int _udevcomplete(int argc, char **argv, void *data __attribute__((unused
 }
 
 #ifndef UDEV_SYNC_SUPPORT
-static const char _cmd_not_supported[] = "Command not supported. Recompile with \"--enable-udev-sync\" to enable.";
+static const char _cmd_not_supported[] = "Command not supported. Recompile with \"--enable-udev_sync\" to enable.";
 
-static int _udevcreatecookie(int argc, char **argv,
-                                 void *data __attribute__((unused)))
+static int _udevcreatecookie(CMD_ARGS)
 {
        log_error(_cmd_not_supported);
 
        return 0;
 }
 
-static int _udevreleasecookie(int argc, char **argv,
-                               void *data __attribute__((unused)))
+static int _udevreleasecookie(CMD_ARGS)
 {
        log_error(_cmd_not_supported);
 
        return 0;
 }
 
-static int _udevcomplete_all(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
+static int _udevcomplete_all(CMD_ARGS)
 {
        log_error(_cmd_not_supported);
 
        return 0;
 }
 
-static int _udevcookies(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
+static int _udevcookies(CMD_ARGS)
 {
        log_error(_cmd_not_supported);
 
@@ -942,11 +1009,9 @@ static int _udevcookies(int argc __attribute__((unused)), char **argv __attribut
 #else  /* UDEV_SYNC_SUPPORT */
 static int _set_up_udev_support(const char *dev_dir)
 {
-       struct udev *udev;
-       const char *udev_dev_dir;
-       size_t udev_dev_dir_len;
        int dirs_diff;
        const char *env;
+       size_t len = strlen(dev_dir), udev_dir_len = strlen(DM_UDEV_DEV_DIR);
 
        if (_switches[NOUDEVSYNC_ARG])
                dm_udev_set_sync_support(0);
@@ -964,14 +1029,6 @@ static int _set_up_udev_support(const char *dev_dir)
                          " defined by --udevcookie option.",
                          _udev_cookie);
 
-       if (!(udev = udev_new()) ||
-           !(udev_dev_dir = udev_get_dev_path(udev)) ||
-           !*udev_dev_dir) {
-               log_error("Could not get udev dev path.");
-               return 0;
-       }
-       udev_dev_dir_len = strlen(udev_dev_dir);
-
        /*
         * Normally, there's always a fallback action by libdevmapper if udev
         * has not done its job correctly, e.g. the nodes were not created.
@@ -983,13 +1040,18 @@ static int _set_up_udev_support(const char *dev_dir)
         * is the same as "dev path" used by libdevmapper.
         */
 
-       /* There's always a slash at the end of dev_dir. But check udev_dev_dir! */
-       if (udev_dev_dir[udev_dev_dir_len - 1] != '/')
-               dirs_diff = strncmp(dev_dir, udev_dev_dir, udev_dev_dir_len);
-       else
-               dirs_diff = strcmp(dev_dir, udev_dev_dir);
 
-       _udev_only = _udev_cookie && !dirs_diff;
+       /*
+        * DM_UDEV_DEV_DIR always has '/' at its end.
+        * If the dev_dir does not have it, be sure
+        * to make the right comparison without the '/' char!
+        */
+       if (dev_dir[len - 1] != '/')
+               udev_dir_len--;
+
+       dirs_diff = udev_dir_len != len ||
+                   strncmp(DM_UDEV_DEV_DIR, dev_dir, len);
+       _udev_only = !dirs_diff && (_udev_cookie || !_switches[VERIFYUDEV_ARG]);
 
        if (dirs_diff) {
                log_debug("The path %s used for creating device nodes that is "
@@ -998,16 +1060,14 @@ static int _set_up_udev_support(const char *dev_dir)
                          "about udev not working correctly while processing "
                          "particular nodes will be suppressed. These nodes "
                          "and symlinks will be managed in each directory "
-                         "separately.", dev_dir, udev_dev_dir);
+                         "separately.", dev_dir, DM_UDEV_DEV_DIR);
                dm_udev_set_checking(0);
        }
 
-       udev_unref(udev);
        return 1;
 }
 
-static int _udevcreatecookie(int argc, char **argv,
-                                 void *data __attribute__((unused)))
+static int _udevcreatecookie(CMD_ARGS)
 {
        uint32_t cookie;
 
@@ -1020,8 +1080,7 @@ static int _udevcreatecookie(int argc, char **argv,
        return 1;
 }
 
-static int _udevreleasecookie(int argc, char **argv,
-                               void *data __attribute__((unused)))
+static int _udevreleasecookie(CMD_ARGS)
 {
        if (argv[1] && !(_udev_cookie = _get_cookie_value(argv[1])))
                return 0;
@@ -1034,6 +1093,7 @@ static int _udevreleasecookie(int argc, char **argv,
        return dm_udev_wait(_udev_cookie);
 }
 
+__attribute__((format(printf, 1, 2)))
 static char _yes_no_prompt(const char *prompt, ...)
 {
        int c = 0, ret = 0;
@@ -1062,16 +1122,25 @@ static char _yes_no_prompt(const char *prompt, ...)
        return ret;
 }
 
-static int _udevcomplete_all(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
+static int _udevcomplete_all(CMD_ARGS)
 {
        int max_id, id, sid;
        struct seminfo sinfo;
        struct semid_ds sdata;
        int counter = 0;
+       int skipped = 0;
+       unsigned age = 0;
+       time_t t;
+
+       if (argc == 2 && (sscanf(argv[1], "%i", &age) != 1)) {
+               log_error("Failed to read age_in_minutes parameter.");
+               return 0;
+       }
 
        if (!_switches[YES_ARG]) {
-               log_warn("This operation will destroy all semaphores with keys "
+               log_warn("This operation will destroy all semaphores %s%.0d%swith keys "
                         "that have a prefix %" PRIu16 " (0x%" PRIx16 ").",
+                        age ? "older than " : "", age, age ? " minutes " : "",
                         DM_COOKIE_MAGIC, DM_COOKIE_MAGIC);
 
                if (_yes_no_prompt("Do you really want to continue? [y/n]: ") == 'n') {
@@ -1092,6 +1161,13 @@ static int _udevcomplete_all(int argc __attribute__((unused)), char **argv __att
                        continue;
 
                if (sdata.sem_perm.__key >> 16 == DM_COOKIE_MAGIC) {
+                       t = time(NULL);
+
+                       if (sdata.sem_ctime + age * 60 > t ||
+                           sdata.sem_otime + age * 60 > t) {
+                               skipped++;
+                               continue;
+                       }
                        if (semctl(sid, 0, IPC_RMID, 0) < 0) {
                                log_error("Could not cleanup notification semaphore "
                                          "with semid %d and cookie value "
@@ -1105,26 +1181,27 @@ static int _udevcomplete_all(int argc __attribute__((unused)), char **argv __att
        }
 
        log_print("%d semaphores with keys prefixed by "
-                 "%" PRIu16 " (0x%" PRIx16 ") destroyed.",
-                 counter, DM_COOKIE_MAGIC, DM_COOKIE_MAGIC);
+                 "%" PRIu16 " (0x%" PRIx16 ") destroyed. %d skipped.",
+                 counter, DM_COOKIE_MAGIC, DM_COOKIE_MAGIC, skipped);
 
        return 1;
 }
 
-static int _udevcookies(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
+static int _udevcookies(CMD_ARGS)
 {
        int max_id, id, sid;
        struct seminfo sinfo;
        struct semid_ds sdata;
        int val;
-       char *time_str;
+       char otime_str[26], ctime_str[26];
+       char *otimes, *ctimes;
 
        if ((max_id = semctl(0, 0, SEM_INFO, &sinfo)) < 0) {
                log_sys_error("sem_ctl", "SEM_INFO");
                return 0;
        }
 
-       printf("cookie       semid      value      last_semop_time\n");
+       printf("Cookie       Semid      Value      Last semop time           Last change time\n");
 
        for (id = 0; id <= max_id; id++) {
                if ((sid = semctl(id, 0, SEM_STAT, &sdata)) < 0)
@@ -1139,10 +1216,14 @@ static int _udevcookies(int argc __attribute__((unused)), char **argv __attribut
                                continue;
                        }
 
-                       time_str = ctime((const time_t *) &sdata.sem_otime);
+                       if ((otimes = ctime_r((const time_t *) &sdata.sem_otime, (char *)&otime_str)))
+                               otime_str[strlen(otimes)-1] = '\0';
+                       if ((ctimes = ctime_r((const time_t *) &sdata.sem_ctime, (char *)&ctime_str)))
+                               ctime_str[strlen(ctimes)-1] = '\0';
 
-                       printf("0x%-10x %-10d %-10d %s", sdata.sem_perm.__key,
-                               sid, val, time_str ? time_str : "unknown\n");
+                       printf("0x%-10x %-10d %-10d %s  %s\n", sdata.sem_perm.__key,
+                               sid, val, otimes ? : "unknown",
+                               ctimes? : "unknown");
                }
        }
 
@@ -1150,7 +1231,7 @@ static int _udevcookies(int argc __attribute__((unused)), char **argv __attribut
 }
 #endif /* UDEV_SYNC_SUPPORT */
 
-static int _version(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
+static int _version(CMD_ARGS)
 {
        char version[80];
 
@@ -1196,6 +1277,13 @@ static int _simple(int task, const char *name, uint32_t event_nr, int display)
        if (_switches[NOLOCKFS_ARG] && !dm_task_skip_lockfs(dmt))
                goto out;
 
+       if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+               goto out;
+
+       /* FIXME: needs to coperate with udev */
+       if (!_set_task_add_node(dmt))
+                goto out;
+
        if (_switches[READAHEAD_ARG] &&
            !dm_task_set_read_ahead(dmt, _int_args[READAHEAD_ARG],
                                    _read_ahead_flags))
@@ -1205,44 +1293,48 @@ static int _simple(int task, const char *name, uint32_t event_nr, int display)
                udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG |
                              DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
 
-       if (_udev_cookie) {
+       if (_udev_cookie)
                cookie = _udev_cookie;
-               if (_udev_only)
-                       udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
-       }
+
+       if (_udev_only)
+               udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
 
        if (udev_wait_flag && !dm_task_set_cookie(dmt, &cookie, udev_flags))
                goto out;
 
-       r = dm_task_run(dmt);
+       if (_switches[RETRY_ARG] && task == DM_DEVICE_REMOVE)
+               dm_task_retry_remove(dmt);
 
-       if (r && display && _switches[VERBOSE_ARG])
-               r = _display_info(dmt);
+       r = dm_task_run(dmt);
 
       out:
        if (!_udev_cookie && udev_wait_flag)
                (void) dm_udev_wait(cookie);
 
+       if (r && display && _switches[VERBOSE_ARG])
+               r = _display_info(dmt);
+
        dm_task_destroy(dmt);
+
        return r;
 }
 
-static int _suspend(int argc, char **argv, void *data __attribute__((unused)))
+static int _suspend(CMD_ARGS)
 {
        return _simple(DM_DEVICE_SUSPEND, argc > 1 ? argv[1] : NULL, 0, 1);
 }
 
-static int _resume(int argc, char **argv, void *data __attribute__((unused)))
+static int _resume(CMD_ARGS)
 {
        return _simple(DM_DEVICE_RESUME, argc > 1 ? argv[1] : NULL, 0, 1);
 }
 
-static int _clear(int argc, char **argv, void *data __attribute__((unused)))
+static int _clear(CMD_ARGS)
 {
        return _simple(DM_DEVICE_CLEAR, argc > 1 ? argv[1] : NULL, 0, 1);
 }
 
-static int _wait(int argc, char **argv, void *data __attribute__((unused)))
+static int _wait(CMD_ARGS)
 {
        const char *name = NULL;
 
@@ -1259,8 +1351,8 @@ static int _wait(int argc, char **argv, void *data __attribute__((unused)))
                       (argc > 1) ? (uint32_t) atoi(argv[argc - 1]) : 0, 1);
 }
 
-static int _process_all(int argc, char **argv, int silent,
-                       int (*fn) (int argc, char **argv, void *data))
+static int _process_all(const struct command *cmd, int argc, char **argv, int silent,
+                       int (*fn) (CMD_ARGS))
 {
        int r = 1;
        struct dm_names *names;
@@ -1271,6 +1363,9 @@ static int _process_all(int argc, char **argv, int silent,
        if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
                return 0;
 
+       if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+               goto out;
+
        if (!dm_task_run(dmt)) {
                r = 0;
                goto out;
@@ -1289,7 +1384,7 @@ static int _process_all(int argc, char **argv, int silent,
 
        do {
                names = (struct dm_names *)((char *) names + next);
-               if (!fn(argc, argv, names))
+               if (!fn(cmd, argc, argv, names, 1))
                        r = 0;
                next = names->next;
        } while (next);
@@ -1319,6 +1414,9 @@ static uint64_t _get_device_size(const char *name)
        if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
                goto out;
 
+       if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+               goto out;
+
        if (!dm_task_run(dmt))
                goto out;
 
@@ -1336,18 +1434,14 @@ static uint64_t _get_device_size(const char *name)
        return size;
 }
 
-static int _error_device(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data)
+static int _error_device(CMD_ARGS)
 {
-       struct dm_names *names = (struct dm_names *) data;
        struct dm_task *dmt;
        const char *name;
        uint64_t size;
        int r = 0;
 
-       if (data)
-               name = names->name;
-       else
-               name = argv[1];
+       name = names ? names->name : argv[1];
 
        size = _get_device_size(name);
 
@@ -1369,6 +1463,9 @@ static int _error_device(int argc __attribute__((unused)), char **argv __attribu
        if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
                goto error;
 
+       if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+               goto error;
+
        if (!dm_task_run(dmt))
                goto error;
 
@@ -1384,22 +1481,22 @@ error:
        return r;
 }
 
-static int _remove(int argc, char **argv, void *data __attribute__((unused)))
+static int _remove(CMD_ARGS)
 {
        if (_switches[FORCE_ARG] && argc > 1)
-               (void) _error_device(argc, argv, NULL);
+               (void) _error_device(cmd, argc, argv, NULL, 0);
 
        return _simple(DM_DEVICE_REMOVE, argc > 1 ? argv[1] : NULL, 0, 0);
 }
 
-static int _count_devices(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
+static int _count_devices(CMD_ARGS)
 {
        _num_devices++;
 
        return 1;
 }
 
-static int _remove_all(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
+static int _remove_all(CMD_ARGS)
 {
        int r;
 
@@ -1410,17 +1507,17 @@ static int _remove_all(int argc __attribute__((unused)), char **argv __attribute
                return r;
 
        _num_devices = 0;
-       r |= _process_all(argc, argv, 1, _count_devices);
+       r |= _process_all(cmd, argc, argv, 1, _count_devices);
 
        /* No devices left? */
        if (!_num_devices)
                return r;
 
-       r |= _process_all(argc, argv, 1, _error_device);
+       r |= _process_all(cmd, argc, argv, 1, _error_device);
        r |= _simple(DM_DEVICE_REMOVE_ALL, "", 0, 0) | dm_mknodes(NULL);
 
        _num_devices = 0;
-       r |= _process_all(argc, argv, 1, _count_devices);
+       r |= _process_all(cmd, argc, argv, 1, _count_devices);
        if (!_num_devices)
                return r;
 
@@ -1437,7 +1534,7 @@ static void _display_dev(struct dm_task *dmt, const char *name)
                printf("%s\t(%u, %u)\n", name, info.major, info.minor);
 }
 
-static int _mknodes(int argc, char **argv, void *data __attribute__((unused)))
+static int _mknodes(CMD_ARGS)
 {
        return dm_mknodes(argc > 1 ? argv[1] : NULL);
 }
@@ -1501,7 +1598,7 @@ static int _exec_command(const char *name)
        return 1;
 }
 
-static int _status(int argc, char **argv, void *data)
+static int _status(CMD_ARGS)
 {
        int r = 0;
        struct dm_task *dmt;
@@ -1509,31 +1606,29 @@ static int _status(int argc, char **argv, void *data)
        uint64_t start, length;
        char *target_type = NULL;
        char *params, *c;
-       int cmd;
-       struct dm_names *names = (struct dm_names *) data;
+       int cmdno;
        const char *name = NULL;
        int matched = 0;
        int ls_only = 0;
        struct dm_info info;
 
-       if (data)
+       if (names)
                name = names->name;
        else {
                if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
-                       return _process_all(argc, argv, 0, _status);
-               if (argc == 2)
-                       name = argv[1];
+                       return _process_all(cmd, argc, argv, 0, _status);
+               name = argv[1];
        }
 
-       if (!strcmp(argv[0], "table"))
-               cmd = DM_DEVICE_TABLE;
+       if (!strcmp(cmd->name, "table"))
+               cmdno = DM_DEVICE_TABLE;
        else
-               cmd = DM_DEVICE_STATUS;
+               cmdno = DM_DEVICE_STATUS;
 
-       if (!strcmp(argv[0], "ls"))
+       if (!strcmp(cmd->name, "ls"))
                ls_only = 1;
 
-       if (!(dmt = dm_task_create(cmd)))
+       if (!(dmt = dm_task_create(cmdno)))
                return 0;
 
        if (!_set_task_device(dmt, name, 0))
@@ -1545,6 +1640,12 @@ static int _status(int argc, char **argv, void *data)
        if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
                goto out;
 
+       if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+               goto out;
+
+       if (_switches[NOFLUSH_ARG] && !dm_task_no_flush(dmt))
+               goto out;
+
        if (!dm_task_run(dmt))
                goto out;
 
@@ -1571,12 +1672,12 @@ static int _status(int argc, char **argv, void *data)
                           _switches[VERBOSE_ARG]) {
                        if (!matched && _switches[VERBOSE_ARG])
                                _display_info(dmt);
-                       if (data && !_switches[VERBOSE_ARG])
+                       if (multiple_devices && !_switches[VERBOSE_ARG])
                                printf("%s: ", name);
                        if (target_type) {
                                /* Suppress encryption key */
                                if (!_switches[SHOWKEYS_ARG] &&
-                                   cmd == DM_DEVICE_TABLE &&
+                                   cmdno == DM_DEVICE_TABLE &&
                                    !strcmp(target_type, "crypt")) {
                                        c = params;
                                        while (*c && *c != ' ')
@@ -1594,7 +1695,7 @@ static int _status(int argc, char **argv, void *data)
                matched = 1;
        } while (next);
 
-       if (data && _switches[VERBOSE_ARG] && matched && !ls_only)
+       if (multiple_devices && _switches[VERBOSE_ARG] && matched && !ls_only)
                printf("\n");
 
        if (matched && _switches[EXEC_ARG] && _command && !_exec_command(name))
@@ -1608,7 +1709,7 @@ static int _status(int argc, char **argv, void *data)
 }
 
 /* Show target names and their version numbers */
-static int _targets(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
+static int _targets(CMD_ARGS)
 {
        int r = 0;
        struct dm_task *dmt;
@@ -1618,6 +1719,9 @@ static int _targets(int argc __attribute__((unused)), char **argv __attribute__(
        if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
                return 0;
 
+       if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+               goto out;
+
        if (!dm_task_run(dmt))
                goto out;
 
@@ -1640,21 +1744,19 @@ static int _targets(int argc __attribute__((unused)), char **argv __attribute__(
        return r;
 }
 
-static int _info(int argc, char **argv, void *data)
+static int _info(CMD_ARGS)
 {
        int r = 0;
 
        struct dm_task *dmt;
-       struct dm_names *names = (struct dm_names *) data;
        char *name = NULL;
 
-       if (data)
+       if (names)
                name = names->name;
        else {
                if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
-                       return _process_all(argc, argv, 0, _info);
-               if (argc == 2)
-                       name = argv[1];
+                       return _process_all(cmd, argc, argv, 0, _info);
+               name = argv[1];
        }
 
        if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
@@ -1669,6 +1771,9 @@ static int _info(int argc, char **argv, void *data)
        if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
                goto out;
 
+       if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+               goto out;
+
        if (!dm_task_run(dmt))
                goto out;
 
@@ -1679,23 +1784,23 @@ static int _info(int argc, char **argv, void *data)
        return r;
 }
 
-static int _deps(int argc, char **argv, void *data)
+static int _deps(CMD_ARGS)
 {
        int r = 0;
        uint32_t i;
        struct dm_deps *deps;
        struct dm_task *dmt;
        struct dm_info info;
-       struct dm_names *names = (struct dm_names *) data;
        char *name = NULL;
+       char dev_name[PATH_MAX];
+       int major, minor;
 
-       if (data)
+       if (names)
                name = names->name;
        else {
                if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
-                       return _process_all(argc, argv, 0, _deps);
-               if (argc == 2)
-                       name = argv[1];
+                       return _process_all(cmd, argc, argv, 0, _deps);
+               name = argv[1];
        }
 
        if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
@@ -1710,6 +1815,9 @@ static int _deps(int argc, char **argv, void *data)
        if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
                goto out;
 
+       if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+               goto out;
+
        if (!dm_task_run(dmt))
                goto out;
 
@@ -1728,17 +1836,24 @@ static int _deps(int argc, char **argv, void *data)
        if (_switches[VERBOSE_ARG])
                _display_info(dmt);
 
-       if (data && !_switches[VERBOSE_ARG])
+       if (multiple_devices && !_switches[VERBOSE_ARG])
                printf("%s: ", name);
        printf("%d dependencies\t:", deps->count);
 
-       for (i = 0; i < deps->count; i++)
-               printf(" (%d, %d)",
-                      (int) MAJOR(deps->device[i]),
-                      (int) MINOR(deps->device[i]));
+       for (i = 0; i < deps->count; i++) {
+               major = (int) MAJOR(deps->device[i]);
+               minor = (int) MINOR(deps->device[i]);
+
+               if ((_dev_name_type == DN_BLK || _dev_name_type == DN_MAP) &&
+                   dm_device_get_name(major, minor, _dev_name_type == DN_BLK,
+                                      dev_name, PATH_MAX))
+                       printf(" (%s)", dev_name);
+               else
+                       printf(" (%d, %d)", major, minor);
+       }
        printf("\n");
 
-       if (data && _switches[VERBOSE_ARG])
+       if (multiple_devices && _switches[VERBOSE_ARG])
                printf("\n");
 
        r = 1;
@@ -1748,12 +1863,21 @@ static int _deps(int argc, char **argv, void *data)
        return r;
 }
 
-static int _display_name(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data)
+static int _display_name(CMD_ARGS)
 {
-       struct dm_names *names = (struct dm_names *) data;
+       char dev_name[PATH_MAX];
+
+       if (!names)
+               return 1;
 
-       printf("%s\t(%d, %d)\n", names->name,
-              (int) MAJOR(names->dev), (int) MINOR(names->dev));
+       if ((_dev_name_type == DN_BLK || _dev_name_type == DN_MAP) &&
+           dm_device_get_name((int) MAJOR(names->dev), (int) MINOR(names->dev),
+                              _dev_name_type == DN_BLK, dev_name, PATH_MAX))
+               printf("%s\t(%s)\n", names->name, dev_name);
+       else
+               printf("%s\t(%d:%d)\n", names->name,
+                                       (int) MAJOR(names->dev),
+                                       (int) MINOR(names->dev));
 
        return 1;
 }
@@ -1764,6 +1888,7 @@ static int _display_name(int argc __attribute__((unused)), char **argv __attribu
 
 enum {
        TR_DEVICE=0,    /* display device major:minor number */
+       TR_BLKDEVNAME,  /* display device kernel name */
        TR_TABLE,
        TR_STATUS,
        TR_ACTIVE,
@@ -1970,6 +2095,11 @@ static void _display_tree_attributes(struct dm_tree_node *node)
                _out_char(']');
 }
 
+/* FIXME Display table or status line. (Disallow both?) */
+static void _display_tree_targets(struct dm_tree_node *node, unsigned depth)
+{
+}
+
 static void _display_tree_node(struct dm_tree_node *node, unsigned depth,
                               unsigned first_child __attribute__((unused)),
                               unsigned last_child, unsigned has_children)
@@ -1978,6 +2108,7 @@ static void _display_tree_node(struct dm_tree_node *node, unsigned depth,
        const char *name;
        const struct dm_info *info;
        int first_on_line = 0;
+       char dev_name[PATH_MAX];
 
        /* Sub-tree for targets has 2 more depth */
        if (depth + 2 > MAX_DEPTH)
@@ -1985,7 +2116,8 @@ static void _display_tree_node(struct dm_tree_node *node, unsigned depth,
 
        name = dm_tree_node_get_name(node);
 
-       if ((!name || !*name) && !_tree_switches[TR_DEVICE])
+       if ((!name || !*name) &&
+           (!_tree_switches[TR_DEVICE] && !_tree_switches[TR_BLKDEVNAME]))
                return;
 
        /* Indicate whether there are more nodes at this depth */
@@ -2010,6 +2142,13 @@ static void _display_tree_node(struct dm_tree_node *node, unsigned depth,
 
        info = dm_tree_node_get_info(node);
 
+       if (_tree_switches[TR_BLKDEVNAME] &&
+           dm_device_get_name(info->major, info->minor, 1, dev_name, PATH_MAX)) {
+               _out_string(name ? " <" : "<");
+               _out_string(dev_name);
+               _out_char('>');
+       }
+
        if (_tree_switches[TR_DEVICE]) {
                _out_string(name ? " (" : "(");
                (void) _out_int(info->major);
@@ -2030,7 +2169,7 @@ static void _display_tree_node(struct dm_tree_node *node, unsigned depth,
 
        if (TR_PRINT_TARGETS) {
                _tree_more[depth + 1] = has_children;
-               // FIXME _display_tree_targets(name, depth + 2);
+               _display_tree_targets(node, depth + 2);
        }
 }
 
@@ -2063,11 +2202,10 @@ static void _display_tree_walk_children(struct dm_tree_node *node,
        }
 }
 
-static int _add_dep(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data)
+static int _add_dep(CMD_ARGS)
 {
-       struct dm_names *names = (struct dm_names *) data;
-
-       if (!dm_tree_add_dev(_dtree, (unsigned) MAJOR(names->dev), (unsigned) MINOR(names->dev)))
+       if (names &&
+           !dm_tree_add_dev(_dtree, (unsigned) MAJOR(names->dev), (unsigned) MINOR(names->dev)))
                return 0;
 
        return 1;
@@ -2076,7 +2214,7 @@ static int _add_dep(int argc __attribute__((unused)), char **argv __attribute__(
 /*
  * Create and walk dependency tree
  */
-static int _build_whole_deptree(void)
+static int _build_whole_deptree(const struct command *cmd)
 {
        if (_dtree)
                return 1;
@@ -2084,17 +2222,15 @@ static int _build_whole_deptree(void)
        if (!(_dtree = dm_tree_create()))
                return 0;
 
-       if (!_process_all(0, NULL, 0, _add_dep))
+       if (!_process_all(cmd, 0, NULL, 0, _add_dep))
                return 0;
 
        return 1;
 }
 
-static int _display_tree(int argc __attribute__((unused)),
-                        char **argv __attribute__((unused)),
-                        void *data __attribute__((unused)))
+static int _display_tree(CMD_ARGS)
 {
-       if (!_build_whole_deptree())
+       if (!_build_whole_deptree(cmd))
                return 0;
 
        _display_tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0);
@@ -2138,6 +2274,38 @@ static int _dm_name_disp(struct dm_report *rh,
        return dm_report_field_string(rh, field, &name);
 }
 
+static int _dm_mangled_name_disp(struct dm_report *rh,
+                                struct dm_pool *mem __attribute__((unused)),
+                                struct dm_report_field *field, const void *data,
+                                void *private __attribute__((unused)))
+{
+       char *name;
+       int r = 0;
+
+       if ((name = dm_task_get_name_mangled((const struct dm_task *) data))) {
+               r = dm_report_field_string(rh, field, (const char * const *) &name);
+               dm_free(name);
+       }
+
+       return r;
+}
+
+static int _dm_unmangled_name_disp(struct dm_report *rh,
+                                  struct dm_pool *mem __attribute__((unused)),
+                                  struct dm_report_field *field, const void *data,
+                                  void *private __attribute__((unused)))
+{
+       char *name;
+       int r = 0;
+
+       if ((name = dm_task_get_name_unmangled((const struct dm_task *) data))) {
+               r = dm_report_field_string(rh, field, (const char * const *) &name);
+               dm_free(name);
+       }
+
+       return r;
+}
+
 static int _dm_uuid_disp(struct dm_report *rh,
                         struct dm_pool *mem __attribute__((unused)),
                         struct dm_report_field *field,
@@ -2151,6 +2319,38 @@ static int _dm_uuid_disp(struct dm_report *rh,
        return dm_report_field_string(rh, field, &uuid);
 }
 
+static int _dm_mangled_uuid_disp(struct dm_report *rh,
+                                struct dm_pool *mem __attribute__((unused)),
+                                struct dm_report_field *field,
+                                const void *data, void *private __attribute__((unused)))
+{
+       char *uuid;
+       int r = 0;
+
+       if ((uuid = dm_task_get_uuid_mangled((const struct dm_task *) data))) {
+               r = dm_report_field_string(rh, field, (const char * const *) &uuid);
+               dm_free(uuid);
+       }
+
+       return r;
+}
+
+static int _dm_unmangled_uuid_disp(struct dm_report *rh,
+                                  struct dm_pool *mem __attribute__((unused)),
+                                  struct dm_report_field *field,
+                                  const void *data, void *private __attribute__((unused)))
+{
+       char *uuid;
+       int r = 0;
+
+       if ((uuid = dm_task_get_uuid_unmangled((const struct dm_task *) data))) {
+               r = dm_report_field_string(rh, field, (const char * const *) &uuid);
+               dm_free(uuid);
+       }
+
+       return r;
+}
+
 static int _dm_read_ahead_disp(struct dm_report *rh,
                               struct dm_pool *mem __attribute__((unused)),
                               struct dm_report_field *field, const void *data,
@@ -2164,6 +2364,24 @@ static int _dm_read_ahead_disp(struct dm_report *rh,
        return dm_report_field_uint32(rh, field, &value);
 }
 
+static int _dm_blk_name_disp(struct dm_report *rh,
+                            struct dm_pool *mem __attribute__((unused)),
+                            struct dm_report_field *field, const void *data,
+                            void *private __attribute__((unused)))
+{
+       char dev_name[PATH_MAX];
+       const char *s = dev_name;
+       const struct dm_info *info = data;
+
+       if (!dm_device_get_name(info->major, info->minor, 1, dev_name, PATH_MAX)) {
+               log_error("Could not resolve block device name for %d:%d.",
+                         info->major, info->minor);
+               return 0;
+       }
+
+       return dm_report_field_string(rh, field, &s);
+}
+
 static int _dm_info_status_disp(struct dm_report *rh,
                                struct dm_pool *mem __attribute__((unused)),
                                struct dm_report_field *field, const void *data,
@@ -2243,7 +2461,7 @@ static int _dm_info_devno_disp(struct dm_report *rh, struct dm_pool *mem,
                               struct dm_report_field *field, const void *data,
                               void *private)
 {
-       char buf[DM_MAX_TYPE_NAME], *repstr;
+       char buf[PATH_MAX], *repstr;
        const struct dm_info *info = data;
 
        if (!dm_pool_begin_object(mem, 8)) {
@@ -2251,10 +2469,17 @@ static int _dm_info_devno_disp(struct dm_report *rh, struct dm_pool *mem,
                return 0;
        }
 
-       if (dm_snprintf(buf, sizeof(buf), "%d:%d",
-                       info->major, info->minor) < 0) {
-               log_error("dm_pool_alloc failed");
-               goto out_abandon;
+       if (private) {
+               if (!dm_device_get_name(info->major, info->minor,
+                                       1, buf, PATH_MAX))
+                       goto out_abandon;
+       }
+       else {
+               if (dm_snprintf(buf, sizeof(buf), "%d:%d",
+                               info->major, info->minor) < 0) {
+                       log_error("dm_pool_alloc failed");
+                       goto out_abandon;
+               }
        }
 
        if (!dm_pool_grow_object(mem, buf, strlen(buf) + 1)) {
@@ -2395,13 +2620,14 @@ static int _dm_tree_parents_count_disp(struct dm_report *rh,
        return dm_report_field_int(rh, field, &num_parent);
 }
 
-static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem,
-                        struct dm_report_field *field, const void *data,
-                        void *private)
+static int _dm_deps_disp_common(struct dm_report *rh, struct dm_pool*mem,
+                               struct dm_report_field *field, const void *data,
+                               void *private, int disp_blk_dev_names)
 {
        const struct dm_deps *deps = data;
-       int i;
-       char buf[DM_MAX_TYPE_NAME], *repstr;
+       char buf[PATH_MAX], *repstr;
+       int major, minor;
+       unsigned i;
 
        if (!dm_pool_begin_object(mem, 16)) {
                log_error("dm_pool_begin_object failed");
@@ -2409,16 +2635,27 @@ static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem,
        }
 
        for (i = 0; i < deps->count; i++) {
-               if (dm_snprintf(buf, sizeof(buf), "%d:%d",
-                      (int) MAJOR(deps->device[i]),
-                      (int) MINOR(deps->device[i])) < 0) {
+               major = (int) MAJOR(deps->device[i]);
+               minor = (int) MINOR(deps->device[i]);
+
+               if (disp_blk_dev_names) {
+                       if (!dm_device_get_name(major, minor, 1, buf, PATH_MAX)) {
+                               log_error("Could not resolve block device "
+                                         "name for %d:%d.", major, minor);
+                               goto out_abandon;
+                       }
+               }
+               else if (dm_snprintf(buf, sizeof(buf), "%d:%d",
+                                    major, minor) < 0) {
                        log_error("dm_snprintf failed");
                        goto out_abandon;
                }
+
                if (!dm_pool_grow_object(mem, buf, 0)) {
                        log_error("dm_pool_grow_object failed");
                        goto out_abandon;
                }
+
                if (i + 1 < deps->count && !dm_pool_grow_object(mem, ",", 1)) {
                        log_error("dm_pool_grow_object failed");
                        goto out_abandon;
@@ -2439,12 +2676,26 @@ static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem,
        return 0;
 }
 
+static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem,
+                        struct dm_report_field *field, const void *data,
+                        void *private)
+{
+       return _dm_deps_disp_common(rh, mem, field, data, private, 0);
+}
+
+static int _dm_deps_blk_names_disp(struct dm_report *rh, struct dm_pool *mem,
+                                  struct dm_report_field *field,
+                                  const void *data, void *private)
+{
+       return _dm_deps_disp_common(rh, mem, field, data, private, 1);
+}
+
 static int _dm_subsystem_disp(struct dm_report *rh,
                               struct dm_pool *mem __attribute__((unused)),
                               struct dm_report_field *field, const void *data,
                               void *private __attribute__((unused)))
 {
-       return dm_report_field_string(rh, field, (const char **) data);
+       return dm_report_field_string(rh, field, (const char *const *) data);
 }
 
 static int _dm_vg_name_disp(struct dm_report *rh,
@@ -2453,7 +2704,7 @@ static int _dm_vg_name_disp(struct dm_report *rh,
                             void *private __attribute__((unused)))
 {
 
-       return dm_report_field_string(rh, field, (const char **) data);
+       return dm_report_field_string(rh, field, (const char *const *) data);
 }
 
 static int _dm_lv_name_disp(struct dm_report *rh,
@@ -2462,7 +2713,7 @@ static int _dm_lv_name_disp(struct dm_report *rh,
                             void *private __attribute__((unused)))
 
 {
-       return dm_report_field_string(rh, field, (const char **) data);
+       return dm_report_field_string(rh, field, (const char *const *) data);
 }
 
 static int _dm_lv_layer_name_disp(struct dm_report *rh,
@@ -2471,7 +2722,7 @@ static int _dm_lv_layer_name_disp(struct dm_report *rh,
                                   void *private __attribute__((unused)))
 
 {
-       return dm_report_field_string(rh, field, (const char **) data);
+       return dm_report_field_string(rh, field, (const char *const *) data);
 }
 
 static void *_task_get_obj(void *obj)
@@ -2518,11 +2769,16 @@ static const struct dm_report_object_type _report_types[] = {
 static const struct dm_report_field_type _report_fields[] = {
 /* *INDENT-OFF* */
 FIELD_F(TASK, STR, "Name", 16, dm_name, "name", "Name of mapped device.")
+FIELD_F(TASK, STR, "MangledName", 16, dm_mangled_name, "mangled_name", "Mangled name of mapped device.")
+FIELD_F(TASK, STR, "UnmangledName", 16, dm_unmangled_name, "unmangled_name", "Unmangled name of mapped device.")
 FIELD_F(TASK, STR, "UUID", 32, dm_uuid, "uuid", "Unique (optional) identifier for mapped device.")
+FIELD_F(TASK, STR, "MangledUUID", 32, dm_mangled_uuid, "mangled_uuid", "Mangled unique (optional) identifier for mapped device.")
+FIELD_F(TASK, STR, "UnmangledUUID", 32, dm_unmangled_uuid, "unmangled_uuid", "Unmangled unique (optional) identifier for mapped device.")
 
 /* FIXME Next one should be INFO */
 FIELD_F(TASK, NUM, "RAhead", 6, dm_read_ahead, "read_ahead", "Read ahead in sectors.")
 
+FIELD_F(INFO, STR, "BlkDevName", 16, dm_blk_name, "blkdevname", "Name of block device.")
 FIELD_F(INFO, STR, "Stat", 4, dm_info_status, "attr", "(L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.")
 FIELD_F(INFO, STR, "Tables", 6, dm_info_table_loaded, "tables_loaded", "Which of the live and inactive table slots are filled.")
 FIELD_F(INFO, STR, "Suspended", 9, dm_info_suspended, "suspended", "Whether the device is suspended.")
@@ -2535,8 +2791,9 @@ FIELD_O(INFO, dm_info, NUM, "Targ", target_count, 4, int32, "segments", "Number
 FIELD_O(INFO, dm_info, NUM, "Event", event_nr, 6, uint32, "events", "Number of most recent event.")
 
 FIELD_O(DEPS, dm_deps, NUM, "#Devs", count, 5, int32, "device_count", "Number of devices used by this one.")
-FIELD_F(TREE, STR, "DevNames", 8, dm_deps_names, "devs_used", "List of names of mapped devices used by this one.")
-FIELD_F(DEPS, STR, "DevNos", 6, dm_deps, "devnos_used", "List of device numbers of devices used by this one.")
+FIELD_F(TREE, STR, "DevNamesUsed", 16, dm_deps_names, "devs_used", "List of names of mapped devices used by this one.")
+FIELD_F(DEPS, STR, "DevNosUsed", 16, dm_deps, "devnos_used", "List of device numbers of devices used by this one.")
+FIELD_F(DEPS, STR, "BlkDevNamesUsed", 16, dm_deps_blk_names, "blkdevs_used", "List of names of block devices used by this one.")
 
 FIELD_F(TREE, NUM, "#Refs", 5, dm_tree_parents_count, "device_ref_count", "Number of mapped devices referencing this one.")
 FIELD_F(TREE, STR, "RefNames", 8, dm_tree_parents_names, "names_using_dev", "List of names of mapped devices using this one.")
@@ -2559,7 +2816,7 @@ FIELD_O(NAME, dm_split_name, STR, "LVLayer", lv_layer, 7, dm_lv_layer_name, "lv_
 static const char *default_report_options = "name,major,minor,attr,open,segments,events,uuid";
 static const char *splitname_report_options = "vg_name,lv_name,lv_layer";
 
-static int _report_init(struct command *c)
+static int _report_init(const struct command *cmd)
 {
        char *options = (char *) default_report_options;
        const char *keys = "";
@@ -2570,7 +2827,7 @@ static int _report_init(struct command *c)
        size_t len = 0;
        int r = 0;
 
-       if (c && !strcmp(c->name, "splitname"))
+       if (cmd && !strcmp(cmd->name, "splitname"))
                options = (char *) splitname_report_options;
 
        /* emulate old dmsetup behaviour */
@@ -2616,7 +2873,7 @@ static int _report_init(struct command *c)
        if (_switches[SORT_ARG] && _string_args[SORT_ARG]) {
                keys = _string_args[SORT_ARG];
                buffered = 1;
-               if (c && (!strcmp(c->name, "status") || !strcmp(c->name, "table"))) {
+               if (cmd && (!strcmp(cmd->name, "status") || !strcmp(cmd->name, "table"))) {
                        err("--sort is not yet supported with status and table");
                        goto out;
                }
@@ -2650,7 +2907,7 @@ static int _report_init(struct command *c)
                                       options, separator, flags, keys, NULL)))
                goto out;
 
-       if ((_report_type & DR_TREE) && !_build_whole_deptree()) {
+       if ((_report_type & DR_TREE) && !_build_whole_deptree(cmd)) {
                err("Internal device dependency tree creation failed.");
                goto out;
        }
@@ -2673,56 +2930,149 @@ out:
 /*
  * List devices
  */
-static int _ls(int argc, char **argv, void *data)
+static int _ls(CMD_ARGS)
 {
        if ((_switches[TARGET_ARG] && _target) ||
            (_switches[EXEC_ARG] && _command))
-               return _status(argc, argv, data);
+               return _status(cmd, argc, argv, NULL, 0);
        else if ((_switches[TREE_ARG]))
-               return _display_tree(argc, argv, data);
+               return _display_tree(cmd, 0, NULL, NULL, 0);
        else
-               return _process_all(argc, argv, 0, _display_name);
+               return _process_all(cmd, argc, argv, 0, _display_name);
 }
 
-static int _help(int argc, char **argv, void *data);
+static int _mangle(CMD_ARGS)
+{
+       const char *name, *uuid;
+       char *new_name = NULL, *new_uuid = NULL;
+       struct dm_task *dmt;
+       struct dm_info info;
+       int r = 0;
+       int target_format;
+
+       if (names)
+               name = names->name;
+       else {
+               if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
+                       return _process_all(cmd, argc, argv, 0, _mangle);
+               name = argv[1];
+       }
+
+       if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
+               return 0;
+
+       if (!(_set_task_device(dmt, name, 0)))
+               goto out;
+
+       if (!_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+               goto out;
+
+       if (!dm_task_run(dmt))
+               goto out;
+
+       if (!dm_task_get_info(dmt, &info) || !info.exists)
+               goto out;
+
+       uuid = dm_task_get_uuid(dmt);
+
+       target_format = _switches[MANGLENAME_ARG] ? _int_args[MANGLENAME_ARG]
+                                                 : DEFAULT_DM_NAME_MANGLING;
+
+       if (target_format == DM_STRING_MANGLING_AUTO) {
+               if (strstr(name, "\\x5cx")) {
+                       log_error("The name \"%s\" seems to be mangled more than once. "
+                                 "Manual intervention required to rename the device.", name);
+                       goto out;
+               }
+               if (strstr(uuid, "\\x5cx")) {
+                       log_error("The UUID \"%s\" seems to be mangled more than once. "
+                                 "Manual intervention required to correct the device UUID.", uuid);
+                       goto out;
+               }
+       }
+
+       if (target_format == DM_STRING_MANGLING_NONE) {
+               if (!(new_name = dm_task_get_name_unmangled(dmt)))
+                       goto out;
+               if (!(new_uuid = dm_task_get_uuid_unmangled(dmt)))
+                       goto out;
+       }
+       else {
+               if (!(new_name = dm_task_get_name_mangled(dmt)))
+                       goto out;
+               if (!(new_uuid = dm_task_get_uuid_mangled(dmt)))
+                       goto out;
+       }
+
+       /* We can't rename the UUID, the device must be reactivated manually. */
+       if (strcmp(uuid, new_uuid)) {
+               log_error("%s: %s: UUID in incorrect form. ", name, uuid);
+               log_error("Unable to change device UUID. The device must be deactivated first.");
+               r = 0;
+               goto out;
+       }
+
+       /* Nothing to do if the name is in correct form already. */
+       if (!strcmp(name, new_name)) {
+               log_print("%s: %s: name %salready in correct form", name,
+                         *uuid ? uuid : "[no UUID]", *uuid ? "and UUID " : "");
+               r = 1;
+               goto out;
+       }
+       else
+               log_print("%s: renaming to %s", name, new_name);
+
+       /* Rename to correct form of the name. */
+       r = _do_rename(name, new_name, NULL);
+
+out:
+       dm_free(new_name);
+       dm_free(new_uuid);
+       dm_task_destroy(dmt);
+       return r;
+}
+
+static int _help(CMD_ARGS);
 
 /*
  * Dispatch table
  */
 static struct command _commands[] = {
-       {"help", "[-c|-C|--columns]", 0, 0, _help},
+       {"help", "[-c|-C|--columns]", 0, 0, 0, _help},
        {"create", "<dev_name> [-j|--major <major> -m|--minor <minor>]\n"
          "\t                  [-U|--uid <uid>] [-G|--gid <gid>] [-M|--mode <octal_mode>]\n"
-         "\t                  [-u|uuid <uuid>]\n"
+         "\t                  [-u|uuid <uuid>] [{--addnodeonresume|--addnodeoncreate}]\n"
          "\t                  [--notable | --table <table> | <table_file>]",
-        1, 2, _create},
-       {"remove", "[-f|--force] <device>", 0, 1, _remove},
-       {"remove_all", "[-f|--force]", 0, 0, _remove_all},
-       {"suspend", "[--noflush] <device>", 0, 1, _suspend},
-       {"resume", "<device>", 0, 1, _resume},
-       {"load", "<device> [<table_file>]", 0, 2, _load},
-       {"clear", "<device>", 0, 1, _clear},
-       {"reload", "<device> [<table_file>]", 0, 2, _load},
-       {"rename", "<device> [--setuuid] <new_name_or_uuid>", 1, 2, _rename},
-       {"message", "<device> <sector> <message>", 2, -1, _message},
-       {"ls", "[--target <target_type>] [--exec <command>] [--tree [-o options]]", 0, 0, _ls},
-       {"info", "[<device>]", 0, 1, _info},
-       {"deps", "[<device>]", 0, 1, _deps},
-       {"status", "[<device>] [--target <target_type>]", 0, 1, _status},
-       {"table", "[<device>] [--target <target_type>] [--showkeys]", 0, 1, _status},
-       {"wait", "<device> [<event_nr>]", 0, 2, _wait},
-       {"mknodes", "[<device>]", 0, 1, _mknodes},
-       {"udevcreatecookie", "", 0, 0, _udevcreatecookie},
-       {"udevreleasecookie", "[<cookie>]", 0, 1, _udevreleasecookie},
-       {"udevflags", "<cookie>", 1, 1, _udevflags},
-       {"udevcomplete", "<cookie>", 1, 1, _udevcomplete},
-       {"udevcomplete_all", "", 0, 0, _udevcomplete_all},
-       {"udevcookies", "", 0, 0, _udevcookies},
-       {"targets", "", 0, 0, _targets},
-       {"version", "", 0, 0, _version},
-       {"setgeometry", "<device> <cyl> <head> <sect> <start>", 5, 5, _setgeometry},
-       {"splitname", "<device> [<subsystem>]", 1, 2, _splitname},
-       {NULL, NULL, 0, 0, NULL}
+        1, 2,0,  _create},
+       {"remove", "[-f|--force] <device>", 0, -1, 1, _remove},
+       {"remove_all", "[-f|--force]", 0, 0, 0,  _remove_all},
+       {"suspend", "[--noflush] <device>", 0, -1, 1, _suspend},
+       {"resume", "<device> [{--addnodeonresume|--addnodeoncreate}]", 0, -1, 1, _resume},
+       {"load", "<device> [<table_file>]", 0, 2, 0, _load},
+       {"clear", "<device>", 0, -1, 1, _clear},
+       {"reload", "<device> [<table_file>]", 0, 2, 0, _load},
+       {"wipe_table", "<device>", 0, -1, 1, _error_device},
+       {"rename", "<device> [--setuuid] <new_name_or_uuid>", 1, 2, 0, _rename},
+       {"message", "<device> <sector> <message>", 2, -1, 0, _message},
+       {"ls", "[--target <target_type>] [--exec <command>] [-o options] [--tree]", 0, 0, 0, _ls},
+       {"info", "[<device>]", 0, -1, 1, _info},
+       {"deps", "[-o options] [<device>]", 0, -1, 1, _deps},
+       {"status", "[<device>] [--noflush] [--target <target_type>]", 0, -1, 1, _status},
+       {"table", "[<device>] [--target <target_type>] [--showkeys]", 0, -1, 1, _status},
+       {"wait", "<device> [<event_nr>] [--noflush]", 0, 2, 0, _wait},
+       {"mknodes", "[<device>]", 0, -1, 1, _mknodes},
+       {"mangle", "[<device>]", 0, -1, 1, _mangle},
+       {"udevcreatecookie", "", 0, 0, 0, _udevcreatecookie},
+       {"udevreleasecookie", "[<cookie>]", 0, 1, 0, _udevreleasecookie},
+       {"udevflags", "<cookie>", 1, 1, 0, _udevflags},
+       {"udevcomplete", "<cookie>", 1, 1, 0, _udevcomplete},
+       {"udevcomplete_all", "<age_in_minutes>", 0, 1, 0, _udevcomplete_all},
+       {"udevcookies", "", 0, 0, 0, _udevcookies},
+       {"targets", "", 0, 0, 0, _targets},
+       {"version", "", 0, 0, 0, _version},
+       {"setgeometry", "<device> <cyl> <head> <sect> <start>", 5, 5, 0, _setgeometry},
+       {"splitname", "<device> [<subsystem>]", 1, 2, 0, _splitname},
+       {NULL, NULL, 0, 0, 0, NULL}
 };
 
 static void _usage(FILE *out)
@@ -2731,20 +3081,22 @@ static void _usage(FILE *out)
 
        fprintf(out, "Usage:\n\n");
        fprintf(out, "dmsetup [--version] [-h|--help [-c|-C|--columns]]\n"
-               "        [-v|--verbose [-v|--verbose ...]]\n"
+               "        [--checks] [--manglename <mangling_mode>] [-v|--verbose [-v|--verbose ...]]\n"
                "        [-r|--readonly] [--noopencount] [--nolockfs] [--inactive]\n"
-               "        [--udevcookie] [--noudevrules] [--noudevsync] [-y|--yes]\n"
-               "        [--readahead [+]<sectors>|auto|none]\n"
+               "        [--udevcookie [cookie]] [--noudevrules] [--noudevsync] [--verifyudev]\n"
+               "        [-y|--yes] [--readahead [+]<sectors>|auto|none] [--retry]\n"
                "        [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>]\n"
                "        [--nameprefixes] [--noheadings] [--separator <separator>]\n\n");
        for (i = 0; _commands[i].name; i++)
                fprintf(out, "\t%s %s\n", _commands[i].name, _commands[i].help);
        fprintf(out, "\n<device> may be device name or -u <uuid> or "
                     "-j <major> -m <minor>\n");
+       fprintf(out, "<mangling_mode> is one of 'none', 'auto' and 'hex'.\n");
        fprintf(out, "<fields> are comma-separated.  Use 'help -c' for list.\n");
        fprintf(out, "Table_file contents may be supplied on stdin.\n");
-       fprintf(out, "Tree options are: ascii, utf, vt100; compact, inverted, notrunc;\n"
-                    "                  [no]device, active, open, rw and uuid.\n");
+       fprintf(out, "Options are: devno, devname, blkdevname.\n");
+       fprintf(out, "Tree specific options are: ascii, utf, vt100; compact, inverted, notrunc;\n"
+                    "                           blkdevname, [no]device, active, open, rw and uuid.\n");
        fprintf(out, "\n");
 }
 
@@ -2755,9 +3107,7 @@ static void _losetup_usage(FILE *out)
                     "[-o offset] [-f|loop_device] [file]\n\n");
 }
 
-static int _help(int argc __attribute__((unused)),
-                char **argv __attribute__((unused)),
-                void *data __attribute__((unused)))
+static int _help(CMD_ARGS)
 {
        _usage(stderr);
 
@@ -2770,7 +3120,7 @@ static int _help(int argc __attribute__((unused)),
                        dm_report_free(_report);
                        _report = NULL;
                }
-               (void) _report_init(NULL);
+               (void) _report_init(cmd);
        }
 
        return 1;
@@ -2810,6 +3160,8 @@ static int _process_tree_options(const char *options)
                        ;
                if (!strncmp(s, "device", len))
                        _tree_switches[TR_DEVICE] = 1;
+               else if (!strncmp(s, "blkdevname", len))
+                       _tree_switches[TR_BLKDEVNAME] = 1;
                else if (!strncmp(s, "nodevice", len))
                        _tree_switches[TR_DEVICE] = 0;
                else if (!strncmp(s, "status", len))
@@ -2865,6 +3217,8 @@ static char *_get_abspath(const char *path)
        _path = canonicalize_file_name(path);
 #else
        /* FIXME Provide alternative */
+       log_error(INTERNAL_ERROR "Unimplemented _get_abspath.");
+       _path = NULL;
 #endif
        return _path;
 }
@@ -2872,7 +3226,7 @@ static char *_get_abspath(const char *path)
 static char *parse_loop_device_name(const char *dev, const char *dev_dir)
 {
        char *buf;
-       char *device;
+       char *device = NULL;
 
        if (!(buf = dm_malloc(PATH_MAX)))
                return NULL;
@@ -2890,7 +3244,8 @@ static char *parse_loop_device_name(const char *dev, const char *dev_dir)
                    device[strlen(dev_dir)] != '/')
                        goto error;
 
-               strncpy(buf, strrchr(device, '/') + 1, (size_t) PATH_MAX);
+               strncpy(buf, strrchr(device, '/') + 1, PATH_MAX - 1);
+               buf[PATH_MAX - 1] = '\0';
                dm_free(device);
 
        } else {
@@ -2904,7 +3259,9 @@ static char *parse_loop_device_name(const char *dev, const char *dev_dir)
        return buf;
 
 error:
+       dm_free(device);
        dm_free(buf);
+
        return NULL;
 }
 
@@ -2952,7 +3309,8 @@ static int _loop_table(char *table, size_t tlen, char *file,
        blksize = fsbuf.f_frsize;
 #endif
 
-       close(fd);
+       if (close(fd))
+                log_sys_error("close", file);
 
        if (dm_snprintf(table, tlen, "%llu %llu loop %s %llu\n", 0ULL,
                        (long long unsigned)sectors, file, (long long unsigned)off) < 0)
@@ -2964,15 +3322,15 @@ static int _loop_table(char *table, size_t tlen, char *file,
        return 1;
 
 error:
-       if (fd > -1)
-               close(fd);
+       if (fd > -1 && close(fd))
+               log_sys_error("close", file);
+
        return 0;
 }
 
 static int _process_losetup_switches(const char *base, int *argc, char ***argv,
                                     const char *dev_dir)
 {
-       static int ind;
        int c;
        int encrypt_loop = 0, delete = 0, find = 0, show_all = 0;
        char *device_name = NULL;
@@ -2987,8 +3345,8 @@ static int _process_losetup_switches(const char *base, int *argc, char ***argv,
 
        optarg = 0;
        optind = OPTIND_INIT;
-       while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "ade:fo:v",
-                                           long_options, NULL)) != -1 ) {
+       while ((c = GETOPTLONG_FN(*argc, *argv, "ade:fo:v",
+                                 long_options, NULL)) != -1 ) {
                if (c == ':' || c == '?')
                        return 0;
                if (c == 'a')
@@ -3065,9 +3423,9 @@ static int _process_losetup_switches(const char *base, int *argc, char ***argv,
                return 0;
        }
 
-       /* FIXME Missing free */
        _table = dm_malloc(LOOP_TABLE_SIZE);
-       if (!_loop_table(_table, (size_t) LOOP_TABLE_SIZE, loop_file, device_name, offset)) {
+       if (!_table ||
+           !_loop_table(_table, (size_t) LOOP_TABLE_SIZE, loop_file, device_name, offset)) {
                fprintf(stderr, "Could not build device-mapper table for %s\n", (*argv)[0]);
                dm_free(device_name);
                return 0;
@@ -3080,21 +3438,68 @@ static int _process_losetup_switches(const char *base, int *argc, char ***argv,
        return 1;
 }
 
+static int _process_options(const char *options)
+{
+       const char *s, *end;
+       size_t len;
+
+       /* Tree options are processed separately. */
+       if (_switches[TREE_ARG])
+               return _process_tree_options(_string_args[OPTIONS_ARG]);
+
+       /* Column options are processed separately by _report_init (called later). */
+       if (_switches[COLS_ARG])
+               return 1;
+
+       /* No options specified. */
+       if (!_switches[OPTIONS_ARG])
+               return 1;
+
+       /* Set defaults. */
+       _dev_name_type = DN_DEVNO;
+
+       /* Parse. */
+       for (s = options; s && *s; s++) {
+               len = 0;
+               for (end = s; *end && *end != ','; end++, len++)
+                       ;
+               if (!strncmp(s, "devno", len))
+                       _dev_name_type = DN_DEVNO;
+               else if (!strncmp(s, "blkdevname", len))
+                       _dev_name_type = DN_BLK;
+               else if (!strncmp(s, "devname", len))
+                       _dev_name_type = DN_MAP;
+               else {
+                       fprintf(stderr, "Option not recognised: %s\n", s);
+                       return 0;
+               }
+
+               if (!*end)
+                       break;
+               s = end;
+       }
+
+       return 1;
+}
+
 static int _process_switches(int *argc, char ***argv, const char *dev_dir)
 {
-       char *base, *namebase, *s;
+       const char *base;
+       char *namebase, *s;
        static int ind;
        int c, r;
 
 #ifdef HAVE_GETOPTLONG
        static struct option long_options[] = {
                {"readonly", 0, &ind, READ_ONLY},
+               {"checks", 0, &ind, CHECKS_ARG},
                {"columns", 0, &ind, COLS_ARG},
                {"exec", 1, &ind, EXEC_ARG},
                {"force", 0, &ind, FORCE_ARG},
                {"gid", 1, &ind, GID_ARG},
                {"help", 0, &ind, HELP_ARG},
                {"inactive", 0, &ind, INACTIVE_ARG},
+               {"manglename", 1, &ind, MANGLENAME_ARG},
                {"major", 1, &ind, MAJOR_ARG},
                {"minor", 1, &ind, MINOR_ARG},
                {"mode", 1, &ind, MODE_ARG},
@@ -3109,6 +3514,7 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
                {"noudevsync", 0, &ind, NOUDEVSYNC_ARG},
                {"options", 1, &ind, OPTIONS_ARG},
                {"readahead", 1, &ind, READAHEAD_ARG},
+               {"retry", 0, &ind, RETRY_ARG},
                {"rows", 0, &ind, ROWS_ARG},
                {"separator", 1, &ind, SEPARATOR_ARG},
                {"setuuid", 0, &ind, SETUUID_ARG},
@@ -3122,8 +3528,11 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
                {"unbuffered", 0, &ind, UNBUFFERED_ARG},
                {"unquoted", 0, &ind, UNQUOTED_ARG},
                {"verbose", 1, &ind, VERBOSE_ARG},
+               {"verifyudev", 0, &ind, VERIFYUDEV_ARG},
                {"version", 0, &ind, VERSION_ARG},
                {"yes", 0, &ind, YES_ARG},
+               {"addnodeonresume", 0, &ind, ADD_NODE_ON_RESUME_ARG},
+               {"addnodeoncreate", 0, &ind, ADD_NODE_ON_CREATE_ARG},
                {0, 0, 0, 0}
        };
 #else
@@ -3137,8 +3546,11 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
        memset(&_int_args, 0, sizeof(_int_args));
        _read_ahead_flags = 0;
 
-       namebase = strdup((*argv)[0]);
-       base = basename(namebase);
+       if (!(namebase = strdup((*argv)[0]))) {
+               fprintf(stderr, "Failed to duplicate name.\n");
+               return 0;
+       }
+       base = dm_basename(namebase);
 
        if (!strcmp(base, "devmap_name")) {
                free(namebase);
@@ -3221,6 +3633,12 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
                }
                if (c == 'y' || ind == YES_ARG)
                        _switches[YES_ARG]++;
+               if (ind == ADD_NODE_ON_RESUME_ARG)
+                       _switches[ADD_NODE_ON_RESUME_ARG]++;
+               if (ind == ADD_NODE_ON_CREATE_ARG)
+                       _switches[ADD_NODE_ON_CREATE_ARG]++;
+               if (ind == CHECKS_ARG)
+                       _switches[CHECKS_ARG]++;
                if (ind == UDEVCOOKIE_ARG) {
                        _switches[UDEVCOOKIE_ARG]++;
                        _udev_cookie = _get_cookie_value(optarg);
@@ -3229,6 +3647,8 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
                        _switches[NOUDEVRULES_ARG]++;
                if (ind == NOUDEVSYNC_ARG)
                        _switches[NOUDEVSYNC_ARG]++;
+               if (ind == VERIFYUDEV_ARG)
+                       _switches[VERIFYUDEV_ARG]++;
                if (c == 'G' || ind == GID_ARG) {
                        _switches[GID_ARG]++;
                        _int_args[GID_ARG] = atoi(optarg);
@@ -3242,32 +3662,46 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
                        /* FIXME Accept modes as per chmod */
                        _int_args[MODE_ARG] = (int) strtol(optarg, NULL, 8);
                }
-               if ((ind == EXEC_ARG)) {
+               if (ind == EXEC_ARG) {
                        _switches[EXEC_ARG]++;
                        _command = optarg;
                }
-               if ((ind == TARGET_ARG)) {
+               if (ind == TARGET_ARG) {
                        _switches[TARGET_ARG]++;
                        _target = optarg;
                }
-               if ((ind == INACTIVE_ARG))
-                       _switches[INACTIVE_ARG]++;
-               if ((ind == NAMEPREFIXES_ARG))
+               if (ind == INACTIVE_ARG)
+                      _switches[INACTIVE_ARG]++;
+               if ((ind == MANGLENAME_ARG)) {
+                       _switches[MANGLENAME_ARG]++;
+                       if (!strcasecmp(optarg, "none"))
+                               _int_args[MANGLENAME_ARG] = DM_STRING_MANGLING_NONE;
+                       else if (!strcasecmp(optarg, "auto"))
+                               _int_args[MANGLENAME_ARG] = DM_STRING_MANGLING_AUTO;
+                       else if (!strcasecmp(optarg, "hex"))
+                               _int_args[MANGLENAME_ARG] = DM_STRING_MANGLING_HEX;
+                       else {
+                               log_error("Unknown name mangling mode");
+                               return 0;
+                       }
+                       dm_set_name_mangling_mode((dm_string_mangling_t) _int_args[MANGLENAME_ARG]);
+               }
+               if (ind == NAMEPREFIXES_ARG)
                        _switches[NAMEPREFIXES_ARG]++;
-               if ((ind == NOFLUSH_ARG))
+               if (ind == NOFLUSH_ARG)
                        _switches[NOFLUSH_ARG]++;
-               if ((ind == NOHEADINGS_ARG))
+               if (ind == NOHEADINGS_ARG)
                        _switches[NOHEADINGS_ARG]++;
-               if ((ind == NOLOCKFS_ARG))
+               if (ind == NOLOCKFS_ARG)
                        _switches[NOLOCKFS_ARG]++;
-               if ((ind == NOOPENCOUNT_ARG))
+               if (ind == NOOPENCOUNT_ARG)
                        _switches[NOOPENCOUNT_ARG]++;
-               if ((ind == READAHEAD_ARG)) {
+               if (ind == READAHEAD_ARG) {
                        _switches[READAHEAD_ARG]++;
                        if (!strcasecmp(optarg, "auto"))
                                _int_args[READAHEAD_ARG] = DM_READ_AHEAD_AUTO;
                        else if (!strcasecmp(optarg, "none"))
-                               _int_args[READAHEAD_ARG] = DM_READ_AHEAD_NONE;
+                               _int_args[READAHEAD_ARG] = DM_READ_AHEAD_NONE;
                        else {
                                for (s = optarg; isspace(*s); s++)
                                        ;
@@ -3282,21 +3716,26 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
                                }
                        }
                }
-               if ((ind == ROWS_ARG))
+               if (ind == RETRY_ARG)
+                       _switches[RETRY_ARG]++;
+               if (ind == ROWS_ARG)
                        _switches[ROWS_ARG]++;
-               if ((ind == SETUUID_ARG))
+               if (ind == SETUUID_ARG)
                        _switches[SETUUID_ARG]++;
-               if ((ind == SHOWKEYS_ARG))
+               if (ind == SHOWKEYS_ARG)
                        _switches[SHOWKEYS_ARG]++;
-               if ((ind == TABLE_ARG)) {
+               if (ind == TABLE_ARG) {
                        _switches[TABLE_ARG]++;
-                       _table = optarg;
+                       if (!(_table = dm_strdup(optarg))) {
+                               log_error("Could not allocate memory for table string.");
+                               return 0;
+                       }
                }
-               if ((ind == TREE_ARG))
+               if (ind == TREE_ARG)
                        _switches[TREE_ARG]++;
-               if ((ind == UNQUOTED_ARG))
+               if (ind == UNQUOTED_ARG)
                        _switches[UNQUOTED_ARG]++;
-               if ((ind == VERSION_ARG))
+               if (ind == VERSION_ARG)
                        _switches[VERSION_ARG]++;
        }
 
@@ -3310,7 +3749,7 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
                return 0;
        }
 
-       if (_switches[TREE_ARG] && !_process_tree_options(_string_args[OPTIONS_ARG]))
+       if (!_process_options(_string_args[OPTIONS_ARG]))
                return 0;
 
        if (_switches[TABLE_ARG] && _switches[NOTABLE_ARG]) {
@@ -3318,6 +3757,11 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
                return 0;
        }
 
+       if (_switches[ADD_NODE_ON_RESUME_ARG] && _switches[ADD_NODE_ON_CREATE_ARG]) {
+               fprintf(stderr, "--addnodeonresume and --addnodeoncreate are incompatible.\n");
+               return 0;
+       }
+
        *argv += optind;
        *argc -= optind;
        return 1;
@@ -3325,9 +3769,10 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
 
 int main(int argc, char **argv)
 {
-       struct command *c;
        int r = 1;
        const char *dev_dir;
+       const struct command *cmd;
+       int multiple_devices;
 
        (void) setlocale(LC_ALL, "");
 
@@ -3346,12 +3791,12 @@ int main(int argc, char **argv)
        }
 
        if (_switches[HELP_ARG]) {
-               c = _find_command("help");
+               cmd = _find_command("help");
                goto doit;
        }
 
        if (_switches[VERSION_ARG]) {
-               c = _find_command("version");
+               cmd = _find_command("version");
                goto doit;
        }
 
@@ -3360,27 +3805,30 @@ int main(int argc, char **argv)
                goto out;
        }
 
-       if (!(c = _find_command(argv[0]))) {
+       if (!(cmd = _find_command(argv[0]))) {
                fprintf(stderr, "Unknown command\n");
                _usage(stderr);
                goto out;
        }
 
-       if (argc < c->min_args + 1 ||
-           (c->max_args >= 0 && argc > c->max_args + 1)) {
+       if (argc < cmd->min_args + 1 ||
+           (cmd->max_args >= 0 && argc > cmd->max_args + 1)) {
                fprintf(stderr, "Incorrect number of arguments\n");
                _usage(stderr);
                goto out;
        }
 
-       if (!_switches[COLS_ARG] && !strcmp(c->name, "splitname"))
+       if (!_switches[COLS_ARG] && !strcmp(cmd->name, "splitname"))
                _switches[COLS_ARG]++;
 
+       if (!strcmp(cmd->name, "mangle"))
+               dm_set_name_mangling_mode(DM_STRING_MANGLING_NONE);
+
        if (_switches[COLS_ARG]) {
-               if (!_report_init(c))
+               if (!_report_init(cmd))
                        goto out;
                if (!_report) {
-                       if (!strcmp(c->name, "info"))
+                       if (!strcmp(cmd->name, "info"))
                                r = 0;  /* info -c -o help */
                        goto out;
                }
@@ -3392,10 +3840,14 @@ int main(int argc, char **argv)
        #endif
 
       doit:
-       if (!c->fn(argc, argv, NULL)) {
-               fprintf(stderr, "Command failed\n");
-               goto out;
-       }
+       multiple_devices = (cmd->repeatable_cmd && argc != 2 &&
+                           (argc != 1 || (!_switches[UUID_ARG] && !_switches[MAJOR_ARG])));
+       do {
+               if (!cmd->fn(cmd, argc--, argv++, NULL, multiple_devices)) {
+                       fprintf(stderr, "Command failed\n");
+                       goto out;
+               }
+       } while (cmd->repeatable_cmd && argc > 1);
 
        r = 0;
 
@@ -3408,5 +3860,7 @@ out:
        if (_dtree)
                dm_tree_free(_dtree);
 
+       dm_free(_table);
+
        return r;
 }
index 981147c58b08c10d8817f48afd602f2d3bfd665f..c5f52265269590e26b9934ec3ccc26c592b11fed 100644 (file)
@@ -19,7 +19,7 @@ int dumpconfig(struct cmd_context *cmd, int argc, char **argv)
 {
        const char *file = arg_str_value(cmd, file_ARG, NULL);
 
-       if (!write_config_file(cmd->cft, file, argc, argv)) {
+       if (!config_write(cmd->cft, file, argc, argv)) {
                stack;
                return ECMD_FAILED;
        }
index 8161d227f6ccdbeb1ad8f1931f1142e3755310ad..04facdd10b65dfeba3c0a7d2d4821f1f177a9d39 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -43,6 +43,20 @@ static int lvchange_permission(struct cmd_context *cmd,
                return 0;
        }
 
+       /* Not allowed to change permissions on RAID sub-LVs directly */
+       if ((lv->status & RAID_META) || (lv->status & RAID_IMAGE)) {
+               log_error("Cannot change permissions of RAID %s \"%s\"",
+                         (lv->status & RAID_IMAGE) ? "image" :
+                         "metadata area", lv->name);
+               return 0;
+       }
+
+       if (!(lv_access & LVM_WRITE) && lv_is_thin_pool(lv)) {
+               log_error("Change permissions of thin pool \"%s\" not "
+                         "yes supported.", lv->name);
+               return 0;
+       }
+
        if (lv_access & LVM_WRITE) {
                lv->status |= LVM_WRITE;
                log_verbose("Setting logical volume \"%s\" read/write",
@@ -81,12 +95,90 @@ out:
        return r;
 }
 
+static int lvchange_pool_update(struct cmd_context *cmd,
+                               struct logical_volume *lv)
+{
+       int r = 0;
+       int update = 0;
+       unsigned val;
+       thin_discards_t discards;
+
+       if (!lv_is_thin_pool(lv)) {
+               log_error("Logical volume \"%s\" is not a thin pool.", lv->name);
+               return 0;
+       }
+
+       if (arg_count(cmd, discards_ARG)) {
+               discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_IGNORE);
+               if (discards != first_seg(lv)->discards) {
+                       if ((discards != THIN_DISCARDS_IGNORE) &&
+                                (first_seg(lv)->chunk_size &
+                                 (first_seg(lv)->chunk_size - 1)))
+                               log_error("Cannot change discards state for "
+                                         "logical volume \"%s\" "
+                                         "with non power of 2 chunk size.", lv->name);
+                       else if (((discards == THIN_DISCARDS_IGNORE) ||
+                            (first_seg(lv)->discards == THIN_DISCARDS_IGNORE)) &&
+                           lv_is_active(lv))
+                               log_error("Cannot change discards state for active "
+                                         "logical volume \"%s\".", lv->name);
+                       else {
+                               first_seg(lv)->discards = discards;
+                               update++;
+                       }
+               } else
+                       log_error("Logical volume \"%s\" already uses --discards %s.",
+                                 lv->name, get_pool_discards_name(discards));
+       }
+
+       if (arg_count(cmd, zero_ARG)) {
+               val = arg_uint_value(cmd, zero_ARG, 1);
+               if (val != first_seg(lv)->zero_new_blocks) {
+                       first_seg(lv)->zero_new_blocks = val;
+                       update++;
+               } else
+                       log_error("Logical volume \"%s\" already %szero new blocks.",
+                                 lv->name, val ? "" : "does not ");
+       }
+
+       if (!update)
+               return 0;
+
+       log_very_verbose("Updating logical volume \"%s\" on disk(s).", lv->name);
+       if (!vg_write(lv->vg))
+               return_0;
+
+       if (!suspend_lv_origin(cmd, lv)) {
+               log_error("Failed to update active %s/%s (deactivation is needed).",
+                         lv->vg->name, lv->name);
+               vg_revert(lv->vg);
+               goto out;
+       }
+
+       if (!vg_commit(lv->vg)) {
+               if (!resume_lv_origin(cmd, lv))
+                       stack;
+               goto_out;
+       }
+
+       if (!resume_lv_origin(cmd, lv)) {
+               log_error("Problem reactivating %s.", lv->name);
+               goto out;
+       }
+
+       r = 1;
+out:
+       backup(lv->vg);
+       return r;
+}
+
 static int lvchange_monitoring(struct cmd_context *cmd,
                               struct logical_volume *lv)
 {
        struct lvinfo info;
 
-       if (!lv_info(cmd, lv, 0, &info, 0, 0) || !info.exists) {
+       if (!lv_info(cmd, lv, lv_is_thin_pool(lv) ? 1 : 0,
+                    &info, 0, 0) || !info.exists) {
                log_error("Logical volume, %s, is not active", lv->name);
                return 0;
        }
@@ -118,12 +210,20 @@ static int lvchange_background_polling(struct cmd_context *cmd,
        return 1;
 }
 
-static int lvchange_availability(struct cmd_context *cmd,
-                                struct logical_volume *lv)
+static int _lvchange_activate(struct cmd_context *cmd, struct logical_volume *lv)
 {
        int activate;
 
-       activate = arg_uint_value(cmd, available_ARG, 0);
+       activate = arg_uint_value(cmd, activate_ARG, 0);
+
+       if (lv_is_cow(lv) && !lv_is_virtual_origin(origin_from_cow(lv)))
+               lv = origin_from_cow(lv);
+
+       if (activate == CHANGE_AAY) {
+               if (!lv_passes_auto_activation_filter(cmd, lv))
+                       return 1;
+               activate = CHANGE_ALY;
+       }
 
        if (activate == CHANGE_ALN) {
                log_verbose("Deactivating logical volume \"%s\" locally",
@@ -135,7 +235,9 @@ static int lvchange_availability(struct cmd_context *cmd,
                if (!deactivate_lv(cmd, lv))
                        return_0;
        } else {
-               if (lv_is_origin(lv) || (activate == CHANGE_AE)) {
+               if ((activate == CHANGE_AE) ||
+                   lv_is_origin(lv) ||
+                   lv_is_thin_type(lv)) {
                        log_verbose("Activating logical volume \"%s\" "
                                    "exclusively", lv->name);
                        if (!activate_lv_excl(cmd, lv))
@@ -166,18 +268,82 @@ static int lvchange_refresh(struct cmd_context *cmd, struct logical_volume *lv)
        return lv_refresh(cmd, lv);
 }
 
+static int detach_metadata_devices(struct lv_segment *seg, struct dm_list *list)
+{
+       uint32_t s;
+       uint32_t num_meta_lvs;
+       struct cmd_context *cmd = seg->lv->vg->cmd;
+       struct lv_list *lvl;
+
+       num_meta_lvs = seg_is_raid(seg) ? seg->area_count : !!seg->log_lv;
+
+       if (!num_meta_lvs)
+               return_0;
+
+       if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl) * num_meta_lvs)))
+               return_0;
+
+       if (seg_is_raid(seg)) {
+               for (s = 0; s < seg->area_count; s++) {
+                       if (!seg_metalv(seg, s))
+                               return_0; /* Trap this future possibility */
+
+                       lvl[s].lv = seg_metalv(seg, s);
+                       lv_set_visible(lvl[s].lv);
+
+                       dm_list_add(list, &lvl[s].list);
+               }
+               return 1;
+       }
+
+       lvl[0].lv = detach_mirror_log(seg);
+       dm_list_add(list, &lvl[0].list);
+
+       return 1;
+}
+
+static int attach_metadata_devices(struct lv_segment *seg, struct dm_list *list)
+{
+       struct cmd_context *cmd = seg->lv->vg->cmd;
+       struct lv_list *lvl, *tmp;
+
+       if (seg_is_raid(seg)) {
+               dm_list_iterate_items_safe(lvl, tmp, list) {
+                       lv_set_hidden(lvl->lv);
+                       dm_pool_free(cmd->mem, lvl);
+               }
+               return 1;
+       }
+
+       dm_list_iterate_items(lvl, list)
+               break;  /* get first item */
+
+       if (!attach_mirror_log(seg, lvl->lv)) {
+               dm_pool_free(cmd->mem, lvl);
+               return_0;
+       }
+
+       dm_pool_free(cmd->mem, lvl);
+
+       return 1;
+}
+
 static int lvchange_resync(struct cmd_context *cmd,
                              struct logical_volume *lv)
 {
        int active = 0;
        int monitored;
        struct lvinfo info;
-       struct logical_volume *log_lv;
+       struct lv_segment *seg = first_seg(lv);
+       struct dm_list device_list;
+       struct lv_list *lvl;
 
-       if (!(lv->status & MIRRORED)) {
-               log_error("Unable to resync %s because it is not mirrored.",
+       dm_list_init(&device_list);
+
+       if (!(lv->status & MIRRORED) && !seg_is_raid(seg)) {
+               log_error("Unable to resync %s.  It is not RAID or mirrored.",
                          lv->name);
-               return 1;
+               return 0;
        }
 
        if (lv->status & PVMOVE) {
@@ -216,7 +382,8 @@ static int lvchange_resync(struct cmd_context *cmd,
 
        /* Activate exclusively to ensure no nodes still have LV active */
        monitored = dmeventd_monitor_mode();
-       init_dmeventd_monitor(0);
+       if (monitored != DMEVENTD_MONITOR_IGNORE)
+               init_dmeventd_monitor(0);
 
        if (!deactivate_lv(cmd, lv)) {
                log_error("Unable to deactivate %s for resync", lv->name);
@@ -229,81 +396,109 @@ static int lvchange_resync(struct cmd_context *cmd,
                return 0;
        }
 
-       init_dmeventd_monitor(monitored);
-
-       log_lv = first_seg(lv)->log_lv;
+       if (monitored != DMEVENTD_MONITOR_IGNORE)
+               init_dmeventd_monitor(monitored);
+       init_mirror_in_sync(0);
 
-       log_very_verbose("Starting resync of %s%s%s mirror \"%s\"",
+       log_very_verbose("Starting resync of %s%s%s%s \"%s\"",
                         (active) ? "active " : "",
                         vg_is_clustered(lv->vg) ? "clustered " : "",
-                        (log_lv) ? "disk-logged" : "core-logged",
-                        lv->name);
+                        (seg->log_lv) ? "disk-logged " :
+                        seg_is_raid(seg) ? "" : "core-logged ",
+                        seg->segtype->ops->name(seg), lv->name);
 
        /*
-        * If this mirror has a core log (i.e. !log_lv),
+        * If this mirror has a core log (i.e. !seg->log_lv),
         * then simply deactivating/activating will cause
         * it to reset the sync status.  We only need to
         * worry about persistent logs.
         */
-       if (!log_lv && !(lv->status & MIRROR_NOTSYNCED)) {
+       if (!seg_is_raid(seg) && !seg->log_lv) {
+               if (lv->status & LV_NOTSYNCED) {
+                       lv->status &= ~LV_NOTSYNCED;
+                       log_very_verbose("Updating logical volume \"%s\""
+                                        " on disk(s)", lv->name);
+                       if (!vg_write(lv->vg) || !vg_commit(lv->vg)) {
+                               log_error("Failed to update metadata on disk.");
+                               return 0;
+                       }
+               }
+
                if (active && !activate_lv(cmd, lv)) {
                        log_error("Failed to reactivate %s to resynchronize "
                                  "mirror", lv->name);
                        return 0;
                }
+
                return 1;
        }
 
-       lv->status &= ~MIRROR_NOTSYNCED;
+       /*
+        * Now we handle mirrors with log devices
+        */
+       lv->status &= ~LV_NOTSYNCED;
 
-       if (log_lv) {
-               /* Separate mirror log so we can clear it */
-               detach_mirror_log(first_seg(lv));
+       /* Separate mirror log or metadata devices so we can clear them */
+       if (!detach_metadata_devices(seg, &device_list)) {
+               log_error("Failed to clear %s %s for %s",
+                         seg->segtype->name, seg_is_raid(seg) ?
+                         "metadata area" : "mirror log", lv->name);
+               return 0;
+       }
 
-               if (!vg_write(lv->vg)) {
-                       log_error("Failed to write intermediate VG metadata.");
-                       if (!attach_mirror_log(first_seg(lv), log_lv))
-                               stack;
-                       if (active && !activate_lv(cmd, lv))
-                               stack;
-                       return 0;
-               }
+       if (!vg_write(lv->vg)) {
+               log_error("Failed to write intermediate VG metadata.");
+               if (!attach_metadata_devices(seg, &device_list))
+                       stack;
+               if (active && !activate_lv(cmd, lv))
+                       stack;
+               return 0;
+       }
 
-               if (!vg_commit(lv->vg)) {
-                       log_error("Failed to commit intermediate VG metadata.");
-                       if (!attach_mirror_log(first_seg(lv), log_lv))
-                               stack;
-                       if (active && !activate_lv(cmd, lv))
-                               stack;
-                       return 0;
-               }
+       if (!vg_commit(lv->vg)) {
+               log_error("Failed to commit intermediate VG metadata.");
+               if (!attach_metadata_devices(seg, &device_list))
+                       stack;
+               if (active && !activate_lv(cmd, lv))
+                       stack;
+               return 0;
+       }
 
-               backup(lv->vg);
+       backup(lv->vg);
 
-               if (!activate_lv(cmd, log_lv)) {
+       dm_list_iterate_items(lvl, &device_list) {
+               if (!activate_lv(cmd, lvl->lv)) {
                        log_error("Unable to activate %s for mirror log resync",
-                                 log_lv->name);
+                                 lvl->lv->name);
                        return 0;
                }
 
-               log_very_verbose("Clearing log device %s", log_lv->name);
-               if (!set_lv(cmd, log_lv, log_lv->size, 0)) {
-                       log_error("Unable to reset sync status for %s", lv->name);
-                       if (!deactivate_lv(cmd, log_lv))
+               log_very_verbose("Clearing %s device %s",
+                                (seg_is_raid(seg)) ? "metadata" : "log",
+                                lvl->lv->name);
+               if (!set_lv(cmd, lvl->lv, lvl->lv->size, 0)) {
+                       log_error("Unable to reset sync status for %s",
+                                 lv->name);
+                       if (!deactivate_lv(cmd, lvl->lv))
                                log_error("Failed to deactivate log LV after "
                                          "wiping failed");
                        return 0;
                }
 
-               if (!deactivate_lv(cmd, log_lv)) {
-                       log_error("Unable to deactivate log LV %s after wiping "
-                                 "for resync", log_lv->name);
+               if (!deactivate_lv(cmd, lvl->lv)) {
+                       log_error("Unable to deactivate %s LV %s "
+                                 "after wiping for resync",
+                                 (seg_is_raid(seg)) ? "metadata" : "log",
+                                 lvl->lv->name);
                        return 0;
                }
+       }
 
-               /* Put mirror log back in place */
-               if (!attach_mirror_log(first_seg(lv), log_lv))
-                       stack;
+       /* Put metadata sub-LVs back in place */
+       if (!attach_metadata_devices(seg, &device_list)) {
+               log_error("Failed to reattach %s device after clearing",
+                         (seg_is_raid(seg)) ? "metadata" : "log");
+               return 0;
        }
 
        log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
@@ -327,7 +522,7 @@ static int lvchange_alloc(struct cmd_context *cmd, struct logical_volume *lv)
 
        want_contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n");
        alloc = want_contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT;
-       alloc = arg_uint_value(cmd, alloc_ARG, alloc);
+       alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, alloc);
 
        if (alloc == lv->alloc) {
                log_error("Allocation policy of logical volume \"%s\" is "
@@ -426,6 +621,7 @@ static int lvchange_persistent(struct cmd_context *cmd,
 {
        struct lvinfo info;
        int active = 0;
+       int32_t major, minor;
 
        if (!strcmp(arg_str_value(cmd, persistent_ARG, "n"), "n")) {
                if (!(lv->status & FIXED_MINOR)) {
@@ -443,12 +639,26 @@ static int lvchange_persistent(struct cmd_context *cmd,
                        log_error("Minor number must be specified with -My");
                        return 0;
                }
+               if (arg_count(cmd, major_ARG) > 1) {
+                       log_error("Option -j/--major may not be repeated.");
+                       return 0;
+               }
+               if (arg_count(cmd, minor_ARG) > 1) {
+                       log_error("Option --minor may not be repeated.");
+                       return 0;
+               }
                if (!arg_count(cmd, major_ARG) && lv->major < 0) {
                        log_error("Major number must be specified with -My");
                        return 0;
                }
                if (lv_info(cmd, lv, 0, &info, 0, 0) && info.exists)
                        active = 1;
+
+               major = arg_int_value(cmd, major_ARG, lv->major);
+               minor = arg_int_value(cmd, minor_ARG, lv->minor);
+               if (!major_minor_valid(cmd, lv->vg->fid->fmt, major, minor))
+                       return 0;
+
                if (active && !arg_count(cmd, force_ARG) &&
                    yes_no_prompt("Logical volume %s will be "
                                  "deactivated temporarily. "
@@ -467,8 +677,8 @@ static int lvchange_persistent(struct cmd_context *cmd,
                        return 0;
                }
                lv->status |= FIXED_MINOR;
-               lv->minor = arg_int_value(cmd, minor_ARG, lv->minor);
-               lv->major = arg_int_value(cmd, major_ARG, lv->major);
+               lv->minor = minor;
+               lv->major = major;
                log_verbose("Setting persistent device number to (%d, %d) "
                            "for \"%s\"", lv->major, lv->minor, lv->name);
 
@@ -491,24 +701,10 @@ static int lvchange_persistent(struct cmd_context *cmd,
        return 1;
 }
 
-static int lvchange_tag(struct cmd_context *cmd, struct logical_volume *lv,
-                       int arg)
+static int lvchange_tag(struct cmd_context *cmd, struct logical_volume *lv, int arg)
 {
-       const char *tag;
-       struct arg_value_group_list *current_group;
-
-       dm_list_iterate_items(current_group, &cmd->arg_value_groups) {
-               if (!grouped_arg_is_set(current_group->arg_values, arg))
-                       continue;
-
-               if (!(tag = grouped_arg_str_value(current_group->arg_values, arg, NULL))) {
-                       log_error("Failed to get tag");
-                       return 0;
-               }
-
-               if (!lv_change_tag(lv, tag, arg == addtag_ARG))
-                       return_0;
-       }
+       if (!change_tag(cmd, NULL, lv, NULL, arg))
+               return_0;
 
        log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
 
@@ -525,19 +721,22 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
                           void *handle __attribute__((unused)))
 {
        int doit = 0, docmds = 0;
-       int dmeventd_mode, archived = 0;
+       int archived = 0;
        struct logical_volume *origin;
+       char snaps_msg[128];
 
        if (!(lv->vg->status & LVM_WRITE) &&
            (arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
             arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG) ||
+            arg_count(cmd, discards_ARG) ||
+            arg_count(cmd, zero_ARG) ||
             arg_count(cmd, alloc_ARG))) {
                log_error("Only -a permitted with read-only volume "
                          "group \"%s\"", lv->vg->name);
                return EINVALID_CMD_LINE;
        }
 
-       if (lv_is_origin(lv) &&
+       if (lv_is_origin(lv) && !lv_is_thin_volume(lv) &&
            (arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
             arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG) ||
             arg_count(cmd, alloc_ARG))) {
@@ -546,16 +745,29 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
                return ECMD_FAILED;
        }
 
-       if (lv_is_cow(lv) && !lv_is_virtual_origin(origin_from_cow(lv)) &&
-           arg_count(cmd, available_ARG)) {
-               log_error("Can't change snapshot logical volume \"%s\"",
-                         lv->name);
-               return ECMD_FAILED;
+       if (lv_is_cow(lv) && !lv_is_virtual_origin(origin = origin_from_cow(lv)) &&
+           arg_count(cmd, activate_ARG)) {
+               if (origin->origin_count < 2)
+                       snaps_msg[0] = '\0';
+               else if (dm_snprintf(snaps_msg, sizeof(snaps_msg),
+                                    " and %u other snapshot(s)",
+                                    origin->origin_count - 1) < 0) {
+                       log_error("Failed to prepare message.");
+                       return ECMD_FAILED;
+               }
+
+               if (!arg_count(cmd, yes_ARG) &&
+                   (yes_no_prompt("Change of snapshot %s will also change its"
+                                  " origin %s%s. Proceed? [y/n]: ", lv->name,
+                                  origin->name, snaps_msg) == 'n')) {
+                       log_error("Logical volume %s not changed.", lv->name);
+                       return ECMD_FAILED;
+               }
        }
 
        if (lv->status & PVMOVE) {
                log_error("Unable to change pvmove LV %s", lv->name);
-               if (arg_count(cmd, available_ARG))
+               if (arg_count(cmd, activate_ARG))
                        log_error("Use 'pvmove --abort' to abandon a pvmove");
                return ECMD_FAILED;
        }
@@ -572,7 +784,7 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
        }
 
        /* If LV is sparse, activate origin instead */
-       if (arg_count(cmd, available_ARG) && lv_is_cow(lv) &&
+       if (arg_count(cmd, activate_ARG) && lv_is_cow(lv) &&
            lv_is_virtual_origin(origin = origin_from_cow(lv)))
                lv = origin;
 
@@ -582,11 +794,6 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
                return ECMD_FAILED;
        }
 
-       if (!get_activation_monitoring_mode(cmd, lv->vg, &dmeventd_mode))
-               return ECMD_FAILED;
-
-       init_dmeventd_monitor(dmeventd_mode);
-
        /*
         * FIXME: DEFAULT_BACKGROUND_POLLING should be "unspecified".
         * If --poll is explicitly provided use it; otherwise polling
@@ -648,6 +855,17 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
                }
        }
 
+       if (arg_count(cmd, discards_ARG) ||
+           arg_count(cmd, zero_ARG)) {
+               if (!archived && !archive(lv->vg)) {
+                       stack;
+                       return ECMD_FAILED;
+               }
+               archived = 1;
+               doit += lvchange_pool_update(cmd, lv);
+               docmds++;
+       }
+
        /* add tag */
        if (arg_count(cmd, addtag_ARG)) {
                if (!archived && !archive(lv->vg)) {
@@ -671,7 +889,7 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
        }
 
        if (doit)
-               log_print("Logical volume \"%s\" changed", lv->name);
+               log_print_unless_silent("Logical volume \"%s\" changed", lv->name);
 
        if (arg_count(cmd, resync_ARG))
                if (!lvchange_resync(cmd, lv)) {
@@ -679,9 +897,9 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
                        return ECMD_FAILED;
                }
 
-       /* availability change */
-       if (arg_count(cmd, available_ARG)) {
-               if (!lvchange_availability(cmd, lv)) {
+       /* activation change */
+       if (arg_count(cmd, activate_ARG)) {
+               if (!_lvchange_activate(cmd, lv)) {
                        stack;
                        return ECMD_FAILED;
                }
@@ -693,7 +911,7 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
                        return ECMD_FAILED;
                }
 
-       if (!arg_count(cmd, available_ARG) &&
+       if (!arg_count(cmd, activate_ARG) &&
            !arg_count(cmd, refresh_ARG) &&
            arg_count(cmd, monitor_ARG)) {
                if (!lvchange_monitoring(cmd, lv)) {
@@ -702,7 +920,7 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
                }
        }
 
-       if (!arg_count(cmd, available_ARG) &&
+       if (!arg_count(cmd, activate_ARG) &&
            !arg_count(cmd, refresh_ARG) &&
            arg_count(cmd, poll_ARG)) {
                if (!lvchange_background_polling(cmd, lv)) {
@@ -721,24 +939,35 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
 
 int lvchange(struct cmd_context *cmd, int argc, char **argv)
 {
-       int update = /* options other than -a, --refresh, --monitor or --poll */
-               arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
-               arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG) ||
-               arg_count(cmd, addtag_ARG) || arg_count(cmd, deltag_ARG) ||
-               arg_count(cmd, resync_ARG) || arg_count(cmd, alloc_ARG);
+       /*
+        * Options that update metadata should be listed in one of
+        * the two lists below (i.e. options other than -a, --refresh,
+        * --monitor or --poll).
+        */
+       int update_partial_safe = /* options safe to update if partial */
+               arg_count(cmd, contiguous_ARG) ||
+               arg_count(cmd, permission_ARG) ||
+               arg_count(cmd, readahead_ARG) ||
+               arg_count(cmd, persistent_ARG) ||
+               arg_count(cmd, addtag_ARG) ||
+               arg_count(cmd, deltag_ARG);
+       int update_partial_unsafe =
+               arg_count(cmd, resync_ARG) ||
+               arg_count(cmd, alloc_ARG) ||
+               arg_count(cmd, discards_ARG) ||
+               arg_count(cmd, zero_ARG);
+       int update = update_partial_safe || update_partial_unsafe;
 
        if (!update &&
-            !arg_count(cmd, available_ARG) && !arg_count(cmd, refresh_ARG) &&
-            !arg_count(cmd, monitor_ARG) && !arg_count(cmd, poll_ARG) &&
-            /* for persistent_ARG */
-           !arg_count(cmd, minor_ARG) && !arg_count(cmd, major_ARG)) {
-               log_error("Need 1 or more of -a, -C, -j, -m, -M, -p, -r, "
+            !arg_count(cmd, activate_ARG) && !arg_count(cmd, refresh_ARG) &&
+            !arg_count(cmd, monitor_ARG) && !arg_count(cmd, poll_ARG)) {
+               log_error("Need 1 or more of -a, -C, -M, -p, -r, -Z, "
                          "--resync, --refresh, --alloc, --addtag, --deltag, "
-                         "--monitor or --poll");
+                         "--monitor, --poll or --discards");
                return EINVALID_CMD_LINE;
        }
 
-       if (arg_count(cmd, available_ARG) && arg_count(cmd, refresh_ARG)) {
+       if (arg_count(cmd, activate_ARG) && arg_count(cmd, refresh_ARG)) {
                log_error("Only one of -a and --refresh permitted.");
                return EINVALID_CMD_LINE;
        }
@@ -749,7 +978,7 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
                return EINVALID_CMD_LINE;
        }
 
-       if (!update)
+       if (!update || !update_partial_unsafe)
                cmd->handles_missing_pvs = 1;
 
        if (!argc) {
@@ -778,6 +1007,13 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
                return EINVALID_CMD_LINE;
        }
 
+       if (arg_count(cmd, sysinit_ARG) && lvmetad_active() &&
+           arg_uint_value(cmd, activate_ARG, 0) == CHANGE_AAY) {
+               log_warn("lvmetad is active while using --sysinit -a ay, "
+                        "skipping manual activation");
+               return ECMD_PROCESSED;
+       }
+
        return process_each_lv(cmd, argc, argv,
                               update ? READ_FOR_UPDATE : 0, NULL,
                               &lvchange_single);
index 7c7826bbdbb85dfd3520c2ba63a2c8da6e406cbd..132a69db000de9246a412400844d06bf56f0fb47 100644 (file)
@@ -20,6 +20,7 @@
 struct lvconvert_params {
        int snapshot;
        int merge;
+       int merge_mirror;
        int zero;
 
        const char *origin;
@@ -39,16 +40,24 @@ struct lvconvert_params {
        uint32_t stripes;
        uint32_t stripe_size;
 
-       struct segment_type *segtype;
+       const struct segment_type *segtype;
 
        alloc_policy_t alloc;
 
        int pv_count;
        char **pvs;
        struct dm_list *pvh;
-       struct dm_list *failed_pvs;
+
+       int replace_pv_count;
+       char **replace_pvs;
+       struct dm_list *replace_pvh;
 
        struct logical_volume *lv_to_poll;
+
+       uint64_t poolmetadata_size;
+       const char *pool_data_lv_name;
+       const char *pool_metadata_lv_name;
+       thin_discards_t discards;
 };
 
 static int _lvconvert_name_params(struct lvconvert_params *lp,
@@ -81,6 +90,15 @@ static int _lvconvert_name_params(struct lvconvert_params *lp,
                        lp->origin = ptr + 1;
        }
 
+       if (!*pargc && lp->pool_data_lv_name) {
+               if (!lp->vg_name || !validate_name(lp->vg_name)) {
+                       log_error("Please provide a valid volume group name.");
+                       return 0;
+               }
+               lp->lv_name = lp->pool_data_lv_name;
+               return 1; /* Create metadata LV on it's own */
+       }
+
        if (!*pargc) {
                log_error("Please provide logical volume path");
                return 0;
@@ -108,7 +126,10 @@ static int _lvconvert_name_params(struct lvconvert_params *lp,
        if ((ptr = strrchr(lp->lv_name_full, '/')))
                lp->lv_name = ptr + 1;
 
-       if (!apply_lvname_restrictions(lp->lv_name))
+       if (!lp->merge_mirror &&
+           !strstr(lp->lv_name, "_tdata") &&
+           !strstr(lp->lv_name, "_tmeta") &&
+           !apply_lvname_restrictions(lp->lv_name))
                return_0;
 
        if (*pargc && lp->snapshot) {
@@ -116,12 +137,20 @@ static int _lvconvert_name_params(struct lvconvert_params *lp,
                return 0;
        }
 
+       if (lp->pool_data_lv_name && lp->lv_name && lp->poolmetadata_size) {
+               log_error("Please specify either metadata logical volume or its size.");
+               return 0;
+       }
+
        return 1;
 }
 
 static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
                        int argc, char **argv)
 {
+       int i;
+       const char *tmp_str;
+       struct arg_value_group_list *group;
        int region_size;
        int pagesize = lvm_getpagesize();
 
@@ -131,7 +160,7 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
            (arg_count(cmd, mirrorlog_ARG) || arg_count(cmd, mirrors_ARG) ||
             arg_count(cmd, repair_ARG))) {
                log_error("--snapshot or --merge argument cannot be mixed "
-                         "with --mirrors, --repair or --log");
+                         "with --mirrors, --repair or --mirrorlog");
                return 0;
        }
 
@@ -152,6 +181,33 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
                return 0;
        }
 
+       if (arg_count(cmd, thinpool_ARG)) {
+               if (arg_count(cmd, merge_ARG)) {
+                       log_error("--thinpool and --merge are mutually exlusive.");
+                       return 0;
+               }
+               if (arg_count(cmd, mirrors_ARG)) {
+                       log_error("--thinpool and --mirrors are mutually exlusive.");
+                       return 0;
+               }
+               if (arg_count(cmd, repair_ARG)) {
+                       log_error("--thinpool and --repair are mutually exlusive.");
+                       return 0;
+               }
+               if (arg_count(cmd, snapshot_ARG)) {
+                       log_error("--thinpool and --snapshot are mutually exlusive.");
+                       return 0;
+               }
+               if (arg_count(cmd, splitmirrors_ARG)) {
+                       log_error("--thinpool and --splitmirrors are mutually exlusive.");
+                       return 0;
+               }
+               lp->discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_PASSDOWN);
+       } else if (arg_count(cmd, discards_ARG)) {
+               log_error("--discards is only valid with --thinpool.");
+               return 0;
+       }
+
        /*
         * The '--splitmirrors n' argument is equivalent to '--mirrors -n'
         * (note the minus sign), except that it signifies the additional
@@ -159,21 +215,28 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
         * discarding it.
         */
        if (arg_count(cmd, splitmirrors_ARG)) {
-               if (!arg_count(cmd, name_ARG)) {
+               if (!arg_count(cmd, name_ARG) &&
+                   !arg_count(cmd, trackchanges_ARG)) {
                        log_error("Please name the new logical volume using '--name'");
                        return 0;
                }
 
                lp->lv_split_name = arg_value(cmd, name_ARG);
-               if (!apply_lvname_restrictions(lp->lv_split_name))
-                       return_0;
+               if (lp->lv_split_name) {
+                       if (strchr(lp->lv_split_name, '/')) {
+                               if (!(lp->vg_name = extract_vgname(cmd, lp->lv_split_name)))
+                                       return_0;
+
+                               /* Strip VG from lv_split_name */
+                               if ((tmp_str = strrchr(lp->lv_split_name, '/')))
+                                       lp->lv_split_name = tmp_str + 1;
+                       }
 
-               lp->keep_mimages = 1;
-               if (arg_sign_value(cmd, mirrors_ARG, 0) == SIGN_MINUS) {
-                       log_error("Argument to --splitmirrors"
-                                 " cannot be negative");
-                       return 0;
+                       if (!apply_lvname_restrictions(lp->lv_split_name))
+                               return_0;
                }
+
+               lp->keep_mimages = 1;
                lp->mirrors = arg_uint_value(cmd, splitmirrors_ARG, 0);
                lp->mirrors_sign = SIGN_MINUS;
        } else if (arg_count(cmd, name_ARG)) {
@@ -182,8 +245,12 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
                return 0;
        }
 
-       if (arg_count(cmd, merge_ARG))
-               lp->merge = 1;
+       if (arg_count(cmd, merge_ARG)) {
+               if ((argc == 1) && strstr(argv[0], "_rimage_"))
+                       lp->merge_mirror = 1;
+               else
+                       lp->merge = 1;
+       }
 
        if (arg_count(cmd, mirrors_ARG)) {
                /*
@@ -192,10 +259,10 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
                 * versus an additional qualifying argument being added here.
                 */
                lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0);
-               lp->mirrors_sign = arg_sign_value(cmd, mirrors_ARG, 0);
+               lp->mirrors_sign = arg_sign_value(cmd, mirrors_ARG, SIGN_NONE);
        }
 
-       lp->alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
+       lp->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
 
        /* There are three types of lvconvert. */
        if (lp->merge) {        /* Snapshot merge */
@@ -221,7 +288,7 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
                        return 0;
                }
 
-               if (arg_sign_value(cmd, chunksize_ARG, 0) == SIGN_MINUS) {
+               if (arg_sign_value(cmd, chunksize_ARG, SIGN_NONE) == SIGN_MINUS) {
                        log_error("Negative chunk size is invalid");
                        return 0;
                }
@@ -242,15 +309,99 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
                                                 SEG_CANNOT_BE_ZEROED) ?
                                                "n" : "y"), "n");
 
-       } else {        /* Mirrors */
+       } else if (arg_count(cmd, replace_ARG)) { /* RAID device replacement */
+               lp->replace_pv_count = arg_count(cmd, replace_ARG);
+               lp->replace_pvs = dm_pool_alloc(cmd->mem, sizeof(char *) * lp->replace_pv_count);
+               if (!lp->replace_pvs)
+                       return_0;
+
+               i = 0;
+               dm_list_iterate_items(group, &cmd->arg_value_groups) {
+                       if (!grouped_arg_is_set(group->arg_values, replace_ARG))
+                               continue;
+                       if (!(tmp_str = grouped_arg_str_value(group->arg_values,
+                                                             replace_ARG,
+                                                             NULL))) {
+                               log_error("Failed to get '--replace' argument");
+                               return 0;
+                       }
+                       if (!(lp->replace_pvs[i++] = dm_pool_strdup(cmd->mem,
+                                                                   tmp_str)))
+                               return_0;
+               }
+       } else if (arg_count(cmd, thinpool_ARG)) {
+               if (!(lp->pool_data_lv_name = arg_str_value(cmd, thinpool_ARG, NULL))) {
+                       log_error("Missing pool logical volume name.");
+                       return 0;
+               }
+
+               if (arg_count(cmd, poolmetadata_ARG)) {
+                       lp->pool_metadata_lv_name = arg_str_value(cmd, poolmetadata_ARG, "");
+               } else if (arg_count(cmd, poolmetadatasize_ARG)) {
+                       if (arg_sign_value(cmd, poolmetadatasize_ARG, SIGN_NONE) == SIGN_MINUS) {
+                               log_error("Negative pool metadata size is invalid.");
+                               return 0;
+                       }
+                       lp->poolmetadata_size = arg_uint64_value(cmd, poolmetadatasize_ARG, UINT64_C(0));
+
+                       if (lp->poolmetadata_size > (2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE)) {
+                               if (arg_count(cmd, poolmetadatasize_ARG))
+                                       log_warn("WARNING: Maximum supported pool metadata size is 16GB.");
+                               lp->poolmetadata_size = 2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE;
+                       } else if (lp->poolmetadata_size < (2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE)) {
+                               if (arg_count(cmd, poolmetadatasize_ARG))
+                                       log_warn("WARNING: Minimum supported pool metadata size is 2M.");
+                               lp->poolmetadata_size = 2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE;
+                       }
+
+                       log_verbose("Setting pool metadata size to %" PRIu64 " sectors.",
+                                   lp->poolmetadata_size);
+               }
+
+               if (arg_count(cmd, chunksize_ARG)) {
+                       if (arg_sign_value(cmd, chunksize_ARG, SIGN_NONE) == SIGN_MINUS) {
+                               log_error("Negative chunk size is invalid.");
+                               return 0;
+                       }
+                       lp->chunk_size = arg_uint_value(cmd, chunksize_ARG,
+                                                       DM_THIN_MIN_DATA_BLOCK_SIZE);
+
+                       if ((lp->chunk_size < DM_THIN_MIN_DATA_BLOCK_SIZE) ||
+                           (lp->chunk_size > DM_THIN_MAX_DATA_BLOCK_SIZE)) {
+                               log_error("Chunk size must be in the range %uK to %uK.",
+                                         (DM_THIN_MIN_DATA_BLOCK_SIZE / 2),
+                                         (DM_THIN_MAX_DATA_BLOCK_SIZE / 2));
+                               return 0;
+                       }
+               } else
+                       lp->chunk_size = DM_THIN_MIN_DATA_BLOCK_SIZE;
+
+               log_verbose("Setting pool metadata chunk size to %u sectors.",
+                           lp->chunk_size);
+
+               if (arg_count(cmd, zero_ARG))
+                       lp->zero = strcmp(arg_str_value(cmd, zero_ARG, "y"), "n");
+
+               /* If --thinpool contains VG name, extract it. */
+               if ((tmp_str = strchr(lp->pool_data_lv_name, (int) '/'))) {
+                       if (!(lp->vg_name = extract_vgname(cmd, lp->pool_data_lv_name)))
+                               return 0;
+                       /* Strip VG from pool */
+                       lp->pool_data_lv_name = tmp_str + 1;
+               }
+
+               lp->segtype = get_segtype_from_string(cmd, arg_str_value(cmd, type_ARG, "thin-pool"));
+               if (!lp->segtype)
+                       return_0;
+       } else { /* Mirrors (and some RAID functions) */
                if (arg_count(cmd, chunksize_ARG)) {
                        log_error("--chunksize is only available with "
-                                 "snapshots");
+                                 "snapshots or thin pools.");
                        return 0;
                }
 
                if (arg_count(cmd, zero_ARG)) {
-                       log_error("--zero is only available with snapshots");
+                       log_error("--zero is only available with snapshots or thin pools.");
                        return 0;
                }
 
@@ -260,7 +411,7 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
                 */
 
                if (arg_count(cmd, regionsize_ARG)) {
-                       if (arg_sign_value(cmd, regionsize_ARG, 0) ==
+                       if (arg_sign_value(cmd, regionsize_ARG, SIGN_NONE) ==
                                    SIGN_MINUS) {
                                log_error("Negative regionsize is invalid");
                                return 0;
@@ -303,11 +454,12 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
                        return 0;
                }
 
-               if (!(lp->segtype = get_segtype_from_string(cmd, "mirror")))
+               lp->segtype = get_segtype_from_string(cmd, arg_str_value(cmd, type_ARG, "mirror"));
+               if (!lp->segtype)
                        return_0;
        }
 
-       if (activation() && lp->segtype->ops->target_present &&
+       if (activation() && lp->segtype && lp->segtype->ops->target_present &&
            !lp->segtype->ops->target_present(cmd, NULL, NULL)) {
                log_error("%s: Required device-mapper target(s) not "
                          "detected in your kernel", lp->segtype->name);
@@ -319,7 +471,6 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
 
        lp->pv_count = argc;
        lp->pvs = argv;
-       lp->failed_pvs = NULL;
 
        return 1;
 }
@@ -342,7 +493,7 @@ static struct logical_volume *_get_lvconvert_lv(struct cmd_context *cmd __attrib
                                                struct volume_group *vg,
                                                const char *name,
                                                const char *uuid,
-                                               uint32_t lv_type __attribute__((unused)))
+                                               uint64_t lv_type __attribute__((unused)))
 {
        struct logical_volume *lv = find_lv(vg, name);
 
@@ -352,23 +503,12 @@ static struct logical_volume *_get_lvconvert_lv(struct cmd_context *cmd __attrib
        return lv;
 }
 
-static int _finish_lvconvert_mirror(struct cmd_context *cmd,
-                                   struct volume_group *vg,
-                                   struct logical_volume *lv,
-                                   struct dm_list *lvs_changed __attribute__((unused)))
+static int _reload_lv(struct cmd_context *cmd,
+                      struct volume_group *vg,
+                     struct logical_volume *lv)
 {
        int r = 0;
 
-       if (!(lv->status & CONVERTING))
-               return 1;
-
-       if (!collapse_mirrored_lv(lv)) {
-               log_error("Failed to remove temporary sync layer.");
-               return 0;
-       }
-
-       lv->status &= ~CONVERTING;
-
        log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
 
        if (!vg_write(vg))
@@ -381,7 +521,8 @@ static int _finish_lvconvert_mirror(struct cmd_context *cmd,
        }
 
        if (!vg_commit(vg)) {
-               resume_lv(cmd, lv);
+               if (!resume_lv(cmd, lv))
+                       stack;
                goto_out;
        }
 
@@ -393,12 +534,36 @@ static int _finish_lvconvert_mirror(struct cmd_context *cmd,
        }
 
        r = 1;
-       log_print("Logical volume %s converted.", lv->name);
 out:
        backup(vg);
        return r;
 }
 
+static int _finish_lvconvert_mirror(struct cmd_context *cmd,
+                                   struct volume_group *vg,
+                                   struct logical_volume *lv,
+                                   struct dm_list *lvs_changed __attribute__((unused)))
+{
+       if (!(lv->status & CONVERTING))
+               return 1;
+
+       if (!collapse_mirrored_lv(lv)) {
+               log_error("Failed to remove temporary sync layer.");
+               return 0;
+       }
+
+       lv->status &= ~CONVERTING;
+
+       log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
+
+       if (!(_reload_lv(cmd, vg, lv)))
+               return_0;
+
+       log_print_unless_silent("Logical volume %s converted.", lv->name);
+
+       return 1;
+}
+
 static int _finish_lvconvert_merge(struct cmd_context *cmd,
                                   struct volume_group *vg,
                                   struct logical_volume *lv,
@@ -410,7 +575,7 @@ static int _finish_lvconvert_merge(struct cmd_context *cmd,
                return 0;
        }
 
-       log_print("Merge of snapshot into logical volume %s has finished.", lv->name);
+       log_print_unless_silent("Merge of snapshot into logical volume %s has finished.", lv->name);
        if (!lv_remove_single(cmd, snap_seg->cow, DONT_PROMPT)) {
                log_error("Could not remove snapshot %s merged into %s.",
                          snap_seg->cow->name, lv->name);
@@ -433,14 +598,17 @@ static progress_t _poll_merge_progress(struct cmd_context *cmd,
        } else if (percent == PERCENT_INVALID) {
                log_error("%s: Merging snapshot invalidated. Aborting merge.", lv->name);
                return PROGRESS_CHECK_FAILED;
+       } else if (percent == PERCENT_MERGE_FAILED) {
+               log_error("%s: Merge failed. Retry merge or inspect manually.", lv->name);
+               return PROGRESS_CHECK_FAILED;
        }
 
        if (parms->progress_display)
-               log_print("%s: %s: %.1f%%", lv->name, parms->progress_title,
-                         percent_to_float(percent));
+               log_print_unless_silent("%s: %s: %.1f%%", lv->name, parms->progress_title,
+                                       100.0 - percent_to_float(percent));
        else
                log_verbose("%s: %s: %.1f%%", lv->name, parms->progress_title,
-                           percent_to_float(percent));
+                           100.0 - percent_to_float(percent));
 
        if (percent == PERCENT_0)
                return PROGRESS_FINISHED_ALL;
@@ -481,7 +649,7 @@ int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv,
        if (!uuid || !lv_full_name)
                return_0;
 
-       if (!dm_snprintf(lv_full_name, len, "%s/%s", lv->vg->name, lv->name))
+       if (dm_snprintf(lv_full_name, len, "%s/%s", lv->vg->name, lv->name) < 0)
                return_0;
 
        memcpy(uuid, &lv->lvid, sizeof(lv->lvid));
@@ -538,36 +706,51 @@ static int _insert_lvconvert_layer(struct cmd_context *cmd,
        return 1;
 }
 
-static int _area_missing(struct lv_segment *lvseg, int s)
-{
-       if (seg_type(lvseg, s) == AREA_LV) {
-               if (seg_lv(lvseg, s)->status & PARTIAL_LV)
-                       return 1;
-       } else if ((seg_type(lvseg, s) == AREA_PV) &&
-                  (is_missing_pv(seg_pv(lvseg, s))))
-               return 1;
-
-       return 0;
-}
-
-/* FIXME we want to handle mirror stacks here... */
 static int _failed_mirrors_count(struct logical_volume *lv)
 {
        struct lv_segment *lvseg;
        int ret = 0;
-       int s;
+       unsigned s;
 
        dm_list_iterate_items(lvseg, &lv->segments) {
                if (!seg_is_mirrored(lvseg))
                        return -1;
-               for (s = 0; s < lvseg->area_count; s++)
-                       if (_area_missing(lvseg, s))
-                               ret++;
+               for (s = 0; s < lvseg->area_count; s++) {
+                       if (seg_type(lvseg, s) == AREA_LV) {
+                               if (is_temporary_mirror_layer(seg_lv(lvseg, s)))
+                                       ret += _failed_mirrors_count(seg_lv(lvseg, s));
+                               else if (seg_lv(lvseg, s)->status & PARTIAL_LV)
+                                       ++ ret;
+                               else if (seg_type(lvseg, s) == AREA_PV &&
+                                        is_missing_pv(seg_pv(lvseg, s)))
+                                       ++ret;
+                       }
+               }
        }
 
        return ret;
 }
 
+static int _failed_logs_count(struct logical_volume *lv)
+{
+       int ret = 0;
+       unsigned s;
+       struct logical_volume *log_lv = first_seg(lv)->log_lv;
+       if (log_lv && (log_lv->status & PARTIAL_LV)) {
+               if (log_lv->status & MIRRORED)
+                       ret += _failed_mirrors_count(log_lv);
+               else
+                       ret += 1;
+       }
+       for (s = 0; s < first_seg(lv)->area_count; s++) {
+               if (seg_type(first_seg(lv), s) == AREA_LV &&
+                   is_temporary_mirror_layer(seg_lv(first_seg(lv), s)))
+                       ret += _failed_logs_count(seg_lv(first_seg(lv), s));
+       }
+       return ret;
+}
+
+
 static struct dm_list *_failed_pv_list(struct volume_group *vg)
 {
        struct dm_list *failed_pvs;
@@ -684,10 +867,10 @@ static int _get_log_count(struct logical_volume *lv)
        struct logical_volume *log_lv;
 
        log_lv = first_seg(_original_lv(lv))->log_lv;
-       if (!log_lv)
-               return 0;
+       if (log_lv)
+               return lv_mirror_count(log_lv);
 
-       return lv_mirror_count(log_lv);
+       return 0;
 }
 
 static int _lv_update_mirrored_log(struct logical_volume *lv,
@@ -724,8 +907,10 @@ static int _lv_update_log_type(struct cmd_context *cmd,
                               struct dm_list *operable_pvs,
                               int log_count)
 {
-       uint32_t region_size;
        int old_log_count;
+       uint32_t region_size = (lp) ? lp->region_size :
+               first_seg(lv)->region_size;
+       alloc_policy_t alloc = (lp) ? lp->alloc : lv->alloc;
        struct logical_volume *original_lv;
        struct logical_volume *log_lv;
 
@@ -734,18 +919,6 @@ static int _lv_update_log_type(struct cmd_context *cmd,
                return 1;
 
        original_lv = _original_lv(lv);
-       region_size = adjusted_mirror_region_size(lv->vg->extent_size,
-                                                 lv->le_count,
-                                                 lp->region_size);
-
-       /* Add a log where there is none */
-       if (!old_log_count) {
-               if (!add_mirror_log(cmd, original_lv, log_count,
-                                   region_size, operable_pvs, lp->alloc))
-                       return_0;
-               return 1;
-       }
-
        /* Remove an existing log completely */
        if (!log_count) {
                if (!remove_mirror_log(cmd, original_lv, operable_pvs,
@@ -759,13 +932,28 @@ static int _lv_update_log_type(struct cmd_context *cmd,
 
        /* Adding redundancy to the log */
        if (old_log_count < log_count) {
-               log_error("Adding log redundancy not supported yet.");
-               log_error("Try converting the log to 'core' first.");
-               return_0;
+               region_size = adjusted_mirror_region_size(lv->vg->extent_size,
+                                                         lv->le_count,
+                                                         region_size);
+
+               if (!add_mirror_log(cmd, original_lv, log_count,
+                                   region_size, operable_pvs, alloc))
+                       return_0;
+               /*
+                * FIXME: This simple approach won't work in cluster mirrors,
+                *        but it doesn't matter because we don't support
+                *        mirrored logs in cluster mirrors.
+                */
+               if (old_log_count &&
+                   !_reload_lv(cmd, log_lv->vg, log_lv))
+                       return_0;
+
+               return 1;
        }
 
        /* Reducing redundancy of the log */
-       return remove_mirror_images(log_lv, log_count, is_mirror_image_removable, operable_pvs, 1U);
+       return remove_mirror_images(log_lv, log_count,
+                                   is_mirror_image_removable, operable_pvs, 1U);
 }
 
 /*
@@ -790,6 +978,7 @@ static void _remove_missing_empty_pv(struct volume_group *vg, struct dm_list *re
                        vg->free_count -= pvl_vg->pv->pe_count;
                        vg->extent_count -= pvl_vg->pv->pe_count;
                        del_pvl_from_vgs(vg, pvl_vg);
+                       free_pv_fid(pvl_vg->pv);
 
                        removed++;
                }
@@ -960,33 +1149,6 @@ static int _lvconvert_mirrors_parse_params(struct cmd_context *cmd,
        return 1;
 }
 
-static int _reload_lv(struct cmd_context *cmd, struct logical_volume *lv)
-{
-       log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
-
-       if (!vg_write(lv->vg))
-               return_0;
-
-       if (!suspend_lv(cmd, lv)) {
-               log_error("Failed to lock %s", lv->name);
-               vg_revert(lv->vg);
-               return 0;
-       }
-
-       if (!vg_commit(lv->vg)) {
-               if (!resume_lv(cmd, lv))
-                       stack;
-               return_0;
-       }
-
-       log_very_verbose("Updating \"%s\" in kernel", lv->name);
-
-       if (!resume_lv(cmd, lv)) {
-               log_error("Problem reactivating %s", lv->name);
-               return 0;
-       }
-       return 1;
-}
 
 /*
  * _lvconvert_mirrors_aux
@@ -1036,10 +1198,9 @@ static int _lvconvert_mirrors_aux(struct cmd_context *cmd,
                 */
                if (!lv_add_mirrors(cmd, lv, new_mimage_count - 1, lp->stripes,
                                    lp->stripe_size, region_size, new_log_count, operable_pvs,
-                                   lp->alloc, MIRROR_BY_LV)) {
-                       stack;
-                       return 0;
-               }
+                                   lp->alloc, MIRROR_BY_LV))
+                       return_0;
+
                if (lp->wait_completion)
                        lp->need_polling = 1;
 
@@ -1050,7 +1211,7 @@ static int _lvconvert_mirrors_aux(struct cmd_context *cmd,
         * Up-convert m-way mirror to n-way mirror
         */
        if (new_mimage_count > old_mimage_count) {
-               if (lv->status & MIRROR_NOTSYNCED) {
+               if (lv->status & LV_NOTSYNCED) {
                        log_error("Can't add mirror to out-of-sync mirrored "
                                  "LV: use lvchange --resync first.");
                        return 0;
@@ -1079,16 +1240,6 @@ static int _lvconvert_mirrors_aux(struct cmd_context *cmd,
                        return 0;
                }
 
-               /*
-                * Is there already a convert in progress?  We do not
-                * currently allow more than one.
-                */
-               if (find_temporary_mirror(lv) || (lv->status & CONVERTING)) {
-                       log_error("%s is already being converted.  Unable to start another conversion.",
-                                 lv->name);
-                       return 0;
-               }
-
                /*
                 * Log addition/removal should be done before the layer
                 * insertion to make the end result consistent with
@@ -1109,7 +1260,8 @@ static int _lvconvert_mirrors_aux(struct cmd_context *cmd,
 
                /* FIXME: can't have multiple mlogs. force corelog. */
                if (!lv_add_mirrors(cmd, lv,
-                                   new_mimage_count - old_mimage_count, lp->stripes, lp->stripe_size,
+                                   new_mimage_count - old_mimage_count,
+                                   lp->stripes, lp->stripe_size,
                                    region_size, 0U, operable_pvs, lp->alloc,
                                    MIRROR_BY_LV)) {
                        layer_lv = seg_lv(first_seg(lv), 0);
@@ -1145,6 +1297,11 @@ static int _lvconvert_mirrors_aux(struct cmd_context *cmd,
 
                /* Reduce number of mirrors */
                if (lp->keep_mimages) {
+                       if (arg_count(cmd, trackchanges_ARG)) {
+                               log_error("--trackchanges is not available "
+                                         "to 'mirror' segment type");
+                               return 0;
+                       }
                        if (!lv_split_mirror_images(lv, lp->lv_split_name,
                                                    nmc, operable_pvs))
                                return 0;
@@ -1169,9 +1326,50 @@ out:
 
 out_skip_log_convert:
 
-       if (!_reload_lv(cmd, lv))
+       if (!_reload_lv(cmd, lv->vg, lv))
+               return_0;
+
+       return 1;
+}
+
+int mirror_remove_missing(struct cmd_context *cmd,
+                         struct logical_volume *lv, int force)
+{
+       struct dm_list *failed_pvs;
+       int log_count = _get_log_count(lv) - _failed_logs_count(lv);
+
+       if (!(failed_pvs = _failed_pv_list(lv->vg)))
+               return_0;
+
+       /* No point in keeping a log if the result is not a mirror */
+       if (_failed_mirrors_count(lv) + 1 >= lv_mirror_count(lv))
+               log_count = 0;
+
+        if (force && _failed_mirrors_count(lv) == lv_mirror_count(lv)) {
+               log_error("No usable images left in %s.", lv->name);
+               return lv_remove_with_dependencies(cmd, lv, DONT_PROMPT, 0);
+        }
+
+       /*
+        * We must adjust the log first, or the entire mirror
+        * will get stuck during a suspend.
+        */
+       if (!_lv_update_mirrored_log(lv, failed_pvs, log_count))
+               return 0;
+
+       if (_failed_mirrors_count(lv) > 0 &&
+           !lv_remove_mirrors(cmd, lv, _failed_mirrors_count(lv),
+                              log_count ? 0U : 1U,
+                              _is_partial_lv, NULL, 0))
+               return 0;
+
+       if (!_lv_update_log_type(cmd, NULL, lv, failed_pvs,
+                                log_count))
                return 0;
 
+       if (!_reload_lv(cmd, lv->vg, lv))
+               return_0;
+
        return 1;
 }
 
@@ -1187,16 +1385,16 @@ out_skip_log_convert:
  */
 static int _lvconvert_mirrors_repair(struct cmd_context *cmd,
                                     struct logical_volume *lv,
-                                    struct lvconvert_params *lp,
-                                    uint32_t old_mimage_count,
-                                    uint32_t old_log_count)
+                                    struct lvconvert_params *lp)
 {
-       int failed_log = 0;
-       int failed_mirrors = 0;
-       int replace_log = 0;
-       int replace_mirrors = 0;
-       uint32_t new_log_count, log_count;
-       struct logical_volume *log_lv;
+       int failed_logs = 0;
+       int failed_mimages = 0;
+       int replace_logs = 0;
+       int replace_mimages = 0;
+       uint32_t log_count;
+
+       uint32_t original_mimages = lv_mirror_count(lv);
+       uint32_t original_logs = _get_log_count(lv);
 
        cmd->handles_missing_pvs = 1;
        cmd->partial_activation = 1;
@@ -1209,93 +1407,43 @@ static int _lvconvert_mirrors_repair(struct cmd_context *cmd,
                return 1;
        }
 
-       /*
-        * Count the failed mimages - negative if 'lv' is not a mirror
-        */
-       if ((failed_mirrors = _failed_mirrors_count(lv)) < 0)
-               return_0;
+       failed_mimages = _failed_mirrors_count(lv);
+       failed_logs = _failed_logs_count(lv);
 
-       lp->mirrors = old_mimage_count - failed_mirrors;
+       mirror_remove_missing(cmd, lv, 0);
 
-       if (lp->mirrors != old_mimage_count)
+       if (failed_mimages)
                log_error("Mirror status: %d of %d images failed.",
-                         failed_mirrors, old_mimage_count);
+                         failed_mimages, original_mimages);
 
        /*
         * Count the failed log devices
         */
-       new_log_count = old_log_count;
-       log_lv = first_seg(lv)->log_lv;
-       if (log_lv) {
-               new_log_count = lv_mirror_count(log_lv);
-               if (log_lv->status & PARTIAL_LV) {
-                       failed_log = 1;
-                       if (log_lv->status & MIRRORED)
-                               new_log_count -= _failed_mirrors_count(log_lv);
-                       else
-                               new_log_count = 0;
-               }
-       }
-       if (old_log_count != new_log_count)
-               log_error("Mirror log status: %d of %d images failed%s",
-                         old_log_count - new_log_count, old_log_count,
-                         (!new_log_count) ? " - switching to core" : "");
+       if (failed_logs)
+               log_error("Mirror log status: %d of %d images failed.",
+                         failed_logs, original_logs);
 
        /*
         * Find out our policies
         */
-       _lvconvert_mirrors_repair_ask(cmd, failed_log, failed_mirrors,
-                                     &replace_log, &replace_mirrors);
-
-       /*
-        * First phase - remove faulty devices
-        */
-       if (!(lp->failed_pvs = _failed_pv_list(lv->vg)))
-               return_0;
-
-       log_count = new_log_count;
-
-       /*
-        * We must adjust the log first, or the entire mirror
-        * will get stuck during a suspend.
-        */
-       if (!_lv_update_mirrored_log(lv, lp->failed_pvs, log_count))
-               return 0;
-
-       if (lp->mirrors == 1)
-               log_count = 0;
-
-       if (failed_mirrors) {
-               if (!lv_remove_mirrors(cmd, lv, failed_mirrors,
-                                      log_count ? 0U : 1U,
-                                      _is_partial_lv, NULL, 0))
-                       return 0;
-       }
-
-       if (!_lv_update_log_type(cmd, lp, lv, lp->failed_pvs,
-                                log_count))
-               return 0;
-
-       if (!_reload_lv(cmd, lv))
-               return 0;
+       _lvconvert_mirrors_repair_ask(cmd, failed_logs, failed_mimages,
+                                     &replace_logs, &replace_mimages);
 
        /*
         * Second phase - replace faulty devices
         */
-
-       if (replace_mirrors)
-               lp->mirrors = old_mimage_count;
+       lp->mirrors = replace_mimages ? original_mimages : (original_mimages - failed_mimages);
 
        /*
         * It does not make sense to replace the log if the volume is no longer
         * a mirror.
         */
-       if (!replace_mirrors && lp->mirrors == 1)
-               replace_log = 0;
+       if (lp->mirrors == 1)
+               replace_logs = 0;
 
-       log_count = replace_log ? old_log_count : new_log_count;
+       log_count = replace_logs ? original_logs : (original_logs - failed_logs);
 
-       while (replace_mirrors || replace_log) {
+       while (replace_mimages || replace_logs) {
                log_warn("Trying to up-convert to %d images, %d logs.", lp->mirrors, log_count);
                if (_lvconvert_mirrors_aux(cmd, lv, lp, NULL,
                                           lp->mirrors, log_count))
@@ -1310,12 +1458,12 @@ static int _lvconvert_mirrors_repair(struct cmd_context *cmd,
                }
        }
 
-       if (replace_mirrors && lp->mirrors != old_mimage_count)
+       if (replace_mimages && lv_mirror_count(lv) != original_mimages)
                log_warn("WARNING: Failed to replace %d of %d images in volume %s",
-                        old_mimage_count - lp->mirrors, old_mimage_count, lv->name);
-       if (replace_log && log_count != old_log_count)
+                        original_mimages - lv_mirror_count(lv), original_mimages, lv->name);
+       if (replace_logs && _get_log_count(lv) != original_logs)
                log_warn("WARNING: Failed to replace %d of %d logs in volume %s",
-                        old_log_count - log_count, old_log_count, lv->name);
+                        original_logs - _get_log_count(lv), original_logs, lv->name);
 
        /* if (!arg_count(cmd, use_policies_ARG) && (lp->mirrors != old_mimage_count
                                                  || log_count != old_log_count))
@@ -1340,6 +1488,19 @@ static int _lvconvert_mirrors(struct cmd_context *cmd,
        uint32_t new_mimage_count;
        uint32_t new_log_count;
 
+       if (lp->merge_mirror) {
+               log_error("Unable to merge mirror images"
+                         "of segment type 'mirror'");
+               return 0;
+       }
+
+       /* TODO: decide what should be done here */
+       if (lv_is_thin_type(lv)) {
+               log_error("Converting segment type for %s/%s to mirror is not yet supported.",
+                        lv->vg->name, lv->name);
+               return 0;
+       }
+
        /* Adjust mimage and/or log count */
        if (!_lvconvert_mirrors_parse_params(cmd, lv, lp,
                                             &old_mimage_count, &old_log_count,
@@ -1349,8 +1510,8 @@ static int _lvconvert_mirrors(struct cmd_context *cmd,
         if (((old_mimage_count < new_mimage_count && old_log_count > new_log_count) ||
              (old_mimage_count > new_mimage_count && old_log_count < new_log_count)) &&
             lp->pv_count) {
-               log_error("Cannot both allocate and free extents when specifying physical"
-                         " volumes to use.");
+               log_error("Cannot both allocate and free extents when "
+                         "specifying physical volumes to use.");
                log_error("Please specify the operation in two steps.");
                return 0;
         }
@@ -1361,27 +1522,162 @@ static int _lvconvert_mirrors(struct cmd_context *cmd,
                return 1;
 
        if (repair)
-               return _lvconvert_mirrors_repair(cmd, lv, lp,
-                                                old_mimage_count,
-                                                old_log_count);
+               return _lvconvert_mirrors_repair(cmd, lv, lp);
 
        if (!_lvconvert_mirrors_aux(cmd, lv, lp, NULL,
                                    new_mimage_count, new_log_count))
                return 0;
 
        if (!lp->need_polling)
-               log_print("Logical volume %s converted.", lv->name);
+               log_print_unless_silent("Logical volume %s converted.", lv->name);
 
        backup(lv->vg);
        return 1;
 }
 
+static int is_valid_raid_conversion(const struct segment_type *from_segtype,
+                                   const struct segment_type *to_segtype)
+{
+       if (from_segtype == to_segtype)
+               return 1;
+
+       if (!segtype_is_raid(from_segtype) && !segtype_is_raid(to_segtype))
+               return_0;  /* Not converting to or from RAID? */
+
+       return 1;
+}
+
+static void _lvconvert_raid_repair_ask(struct cmd_context *cmd, int *replace_dev)
+{
+       const char *dev_policy = NULL;
+
+       int force = arg_count(cmd, force_ARG);
+       int yes = arg_count(cmd, yes_ARG);
+
+       *replace_dev = 0;
+
+       if (arg_count(cmd, use_policies_ARG)) {
+               dev_policy = find_config_tree_str(cmd, "activation/raid_fault_policy", DEFAULT_RAID_FAULT_POLICY);
+
+               if (!strcmp(dev_policy, "allocate") ||
+                   !strcmp(dev_policy, "replace"))
+                       *replace_dev = 1;
+               /* else if (!strcmp(dev_policy, "anything_else")) -- ignore */
+               return;
+       }
+
+       if (yes) {
+               *replace_dev = 1;
+               return;
+       }
+
+       if (force != PROMPT)
+               return;
+
+       if (yes_no_prompt("Attempt to replace failed RAID images "
+                         "(requires full device resync)? [y/n]: ") == 'y') {
+               *replace_dev = 1;
+       }
+}
+
+static int lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *lp)
+{
+       int replace = 0;
+       int uninitialized_var(image_count);
+       struct dm_list *failed_pvs;
+       struct cmd_context *cmd = lv->vg->cmd;
+       struct lv_segment *seg = first_seg(lv);
+
+       if (!arg_count(cmd, type_ARG))
+               lp->segtype = seg->segtype;
+
+       /* Can only change image count for raid1 and linear */
+       if (arg_count(cmd, mirrors_ARG) &&
+           !seg_is_mirrored(seg) && !seg_is_linear(seg)) {
+               log_error("'--mirrors/-m' is not compatible with %s",
+                         seg->segtype->ops->name(seg));
+               return 0;
+       }
+
+       if (!is_valid_raid_conversion(seg->segtype, lp->segtype)) {
+               log_error("Unable to convert %s/%s from %s to %s",
+                         lv->vg->name, lv->name,
+                         seg->segtype->ops->name(seg), lp->segtype->name);
+               return 0;
+       }
+
+       /* Change number of RAID1 images */
+       if (arg_count(cmd, mirrors_ARG) || arg_count(cmd, splitmirrors_ARG)) {
+               image_count = lv_raid_image_count(lv);
+               if (lp->mirrors_sign == SIGN_PLUS)
+                       image_count += lp->mirrors;
+               else if (lp->mirrors_sign == SIGN_MINUS)
+                       image_count -= lp->mirrors;
+               else
+                       image_count = lp->mirrors + 1;
+
+               if (image_count < 1) {
+                       log_error("Unable to %s images by specified amount",
+                                 arg_count(cmd, splitmirrors_ARG) ?
+                                 "split" : "reduce");
+                       return 0;
+               }
+       }
+
+       if (lp->merge_mirror)
+               return lv_raid_merge(lv);
+
+       if (arg_count(cmd, trackchanges_ARG))
+               return lv_raid_split_and_track(lv, lp->pvh);
+
+       if (arg_count(cmd, splitmirrors_ARG))
+               return lv_raid_split(lv, lp->lv_split_name,
+                                    image_count, lp->pvh);
+
+       if (arg_count(cmd, mirrors_ARG))
+               return lv_raid_change_image_count(lv, image_count, lp->pvh);
+
+       if (arg_count(cmd, type_ARG))
+               return lv_raid_reshape(lv, lp->segtype);
+
+       if (arg_count(cmd, replace_ARG))
+               return lv_raid_replace(lv, lp->replace_pvh, lp->pvh);
+
+       if (arg_count(cmd, repair_ARG)) {
+               _lvconvert_raid_repair_ask(cmd, &replace);
+
+               if (replace) {
+                       if (!(failed_pvs = _failed_pv_list(lv->vg)))
+                               return_0;
+
+                       if (!lv_raid_replace(lv, failed_pvs, lp->pvh)) {
+                               log_error("Failed to replace faulty devices in"
+                                         " %s/%s.", lv->vg->name, lv->name);
+                               return 0;
+                       }
+
+                       log_print_unless_silent("Faulty devices in %s/%s successfully"
+                                               " replaced.", lv->vg->name, lv->name);
+                       return 1;
+               }
+
+               /* "warn" if policy not set to replace */
+               if (arg_count(cmd, use_policies_ARG))
+                       log_error("Use 'lvconvert --repair %s/%s' to "
+                                 "replace failed device",
+                                 lv->vg->name, lv->name);
+               return 1;
+       }
+
+       log_error("Conversion operation not yet supported.");
+       return 0;
+}
+
 static int lvconvert_snapshot(struct cmd_context *cmd,
                              struct logical_volume *lv,
                              struct lvconvert_params *lp)
 {
        struct logical_volume *org;
-       int r = 0;
 
        if (!(org = find_lv(lv->vg, lp->origin))) {
                log_error("Couldn't find origin volume '%s'.", lp->origin);
@@ -1395,7 +1691,7 @@ static int lvconvert_snapshot(struct cmd_context *cmd,
        }
 
        if (org->status & (LOCKED|PVMOVE|MIRRORED) || lv_is_cow(org)) {
-               log_error("Unable to create a snapshot of a %s LV.",
+               log_error("Unable to convert an LV into a snapshot of a %s LV.",
                          org->status & LOCKED ? "locked" :
                          org->status & PVMOVE ? "pvmove" :
                          org->status & MIRRORED ? "mirrored" :
@@ -1422,28 +1718,12 @@ static int lvconvert_snapshot(struct cmd_context *cmd,
        }
 
        /* store vg on disk(s) */
-       if (!vg_write(lv->vg))
+       if (!_reload_lv(cmd, lv->vg, lv))
                return_0;
 
-       if (!suspend_lv(cmd, org)) {
-               log_error("Failed to suspend origin %s", org->name);
-               vg_revert(lv->vg);
-               goto out;
-       }
-
-       if (!vg_commit(lv->vg))
-               goto_out;
+       log_print_unless_silent("Logical volume %s converted to snapshot.", lv->name);
 
-       if (!resume_lv(cmd, org)) {
-               log_error("Problem reactivating origin %s", org->name);
-               goto out;
-       }
-
-       log_print("Logical volume %s converted to snapshot.", lv->name);
-       r = 1;
-out:
-       backup(lv->vg);
-       return r;
+       return 1;
 }
 
 static int lvconvert_merge(struct cmd_context *cmd,
@@ -1485,7 +1765,7 @@ static int lvconvert_merge(struct cmd_context *cmd,
        }
        if (lv_info(cmd, lv, 0, &info, 1, 0)) {
                if (info.open_count) {
-                       log_print("Can't merge when snapshot is open");
+                       log_print_unless_silent("Can't merge when snapshot is open");
                        merge_on_activate = 1;
                }
        }
@@ -1501,8 +1781,8 @@ static int lvconvert_merge(struct cmd_context *cmd,
                if (!vg_commit(lv->vg))
                        return_0;
                r = 1;
-               log_print("Merging of snapshot %s will start "
-                         "next activation.", lv->name);
+               log_print_unless_silent("Merging of snapshot %s will start "
+                                       "next activation.", lv->name);
                goto out;
        }
 
@@ -1528,16 +1808,162 @@ static int lvconvert_merge(struct cmd_context *cmd,
        lp->lv_to_poll = origin;
 
        r = 1;
-       log_print("Merging of volume %s started.", lv->name);
+       log_print_unless_silent("Merging of volume %s started.", lv->name);
 out:
        backup(lv->vg);
        return r;
 }
 
+/*
+ * Thin lvconvert version which
+ *  rename metadata
+ *  convert/layers thinpool over data
+ *  attach metadata
+ */
+static int _lvconvert_thinpool(struct cmd_context *cmd,
+                              struct logical_volume *pool_lv,
+                              struct lvconvert_params *lp)
+{
+       int r = 0;
+       char *name;
+       int len;
+       struct lv_segment *seg;
+       struct logical_volume *data_lv;
+       struct logical_volume *metadata_lv;
+
+       if (lv_is_thin_type(pool_lv)) {
+               log_error("Can't use thin logical volume %s/%s for thin pool data.",
+                         pool_lv->vg->name, pool_lv->name);
+               return 0;
+       }
+
+       /* We are changing target type, so deactivate first */
+       if (!deactivate_lv(cmd, pool_lv)) {
+               log_error("Can't deactivate logical volume %s/%s.",
+                         pool_lv->vg->name, pool_lv->name);
+               return 0;
+       }
+
+       if (lp->pool_metadata_lv_name) {
+               metadata_lv = find_lv(pool_lv->vg, lp->pool_metadata_lv_name);
+               if (!metadata_lv) {
+                       log_error("Unknown metadata LV %s", lp->pool_metadata_lv_name);
+                       return 0;
+               }
+               if (metadata_lv == pool_lv) {
+                       log_error("Can't use same LV for thin data and metadata LV %s",
+                                 lp->pool_metadata_lv_name);
+                       return 0;
+               }
+               if (lv_is_thin_type(metadata_lv)) {
+                       log_error("Can't use thin pool logical volume %s/%s "
+                                 "for thin pool metadata.",
+                                 metadata_lv->vg->name, metadata_lv->name);
+                       return 0;
+               }
+       } else if (arg_count(cmd, poolmetadatasize_ARG)) {
+               /* FIXME: allocate metadata LV! */
+               metadata_lv = NULL;
+               log_error("Uncreated metadata.");
+               return 0;
+       } else {
+               log_error("Uknown metadata.");
+               return 0;
+       }
+
+       len = strlen(pool_lv->name) + 16;
+       if (!(name = dm_pool_alloc(pool_lv->vg->vgmem, len))) {
+               log_error("Cannot allocate new name.");
+               return 0;
+       }
+
+       if (!lv_is_active(metadata_lv)) {
+               if (!deactivate_lv(cmd, metadata_lv)) {
+                       log_error("Can't deactivate logical volume %s/%s.",
+                                 metadata_lv->vg->name, metadata_lv->name);
+                       return 0;
+               }
+               if (!activate_lv_local(cmd, metadata_lv)) {
+                       log_error("Aborting. Failed to activate thin metadata lv.");
+                       return 0;
+               }
+       }
+
+       if (!set_lv(cmd, metadata_lv, UINT64_C(0), 0)) {
+               log_error("Aborting. Failed to wipe thin metadata lv.");
+               return 0;
+       }
+
+       if (!deactivate_lv(cmd, metadata_lv)) {
+               log_error("Aborting. Failed to deactivate thin metadata lv. "
+                         "Manual intervention required.");
+               return 0;
+       }
+
+       if (dm_snprintf(name, len, "%s_tmeta", pool_lv->name) < 0)
+               return_0;
+
+       /* Rename deactivated metadata LV to have _tmeta suffix */
+       /* Implicit checks if metadata_lv is visible */
+       if (!lv_rename_update(cmd, metadata_lv, name, 0))
+               return_0;
+
+       /*
+        * Since we wish to have underlaying dev, to match _tdata
+        * rename data LV first, also checks for visible LV
+        */
+       /* FIXME: any more types prohibited here? */
+       /* FIXME: revert renamed LVs in fail path? */
+
+       /* FIXME: common code with metadata/thin_manip.c  extend_pool() */
+       /* Create layer _tdata */
+       if (!(data_lv = insert_layer_for_lv(pool_lv->vg->cmd, pool_lv,
+                                           pool_lv->status, "_tdata")))
+               return_0;
+
+       seg = first_seg(pool_lv);
+       seg->segtype = lp->segtype;
+       seg->lv->status |= THIN_POOL;
+
+       seg->chunk_size = lp->chunk_size;
+       seg->zero_new_blocks = lp->zero ? 1 : 0;
+       seg->discards = lp->discards;
+       seg->low_water_mark = 0;
+       seg->transaction_id = 0;
+
+       if (!attach_pool_metadata_lv(seg, metadata_lv))
+               return_0;
+
+       /* Drop reference as attach_pool_data_lv() takes it again */
+       remove_seg_from_segs_using_this_lv(data_lv, seg);
+       if (!attach_pool_data_lv(seg, data_lv))
+               return_0;
+
+       if (!vg_write(pool_lv->vg) || !vg_commit(pool_lv->vg))
+               return_0;
+
+       if (!activate_lv_excl(cmd, pool_lv)) {
+               log_error("Failed to activate pool logical volume %s/%s.",
+                         pool_lv->vg->name, pool_lv->name);
+               goto out;
+       }
+
+       log_print_unless_silent("Converted %s/%s to thin pool.",
+                               pool_lv->vg->name, pool_lv->name);
+
+       r = 1;
+out:
+       backup(pool_lv->vg);
+       return r;
+}
+
 static int _lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
                             void *handle)
 {
        struct lvconvert_params *lp = handle;
+       struct dm_list *failed_pvs;
+       struct lvinfo info;
+       percent_t snap_percent;
 
        if (lv->status & LOCKED) {
                log_error("Cannot convert locked LV %s", lv->name);
@@ -1555,19 +1981,30 @@ static int _lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
                return ECMD_FAILED;
        }
 
-       if (arg_count(cmd, repair_ARG) && !(lv->status & MIRRORED)) {
+       if (arg_count(cmd, repair_ARG) &&
+           !(lv->status & MIRRORED) && !(lv->status & RAID)) {
                if (arg_count(cmd, use_policies_ARG))
                        return ECMD_PROCESSED; /* nothing to be done here */
                log_error("Can't repair non-mirrored LV \"%s\".", lv->name);
                return ECMD_FAILED;
        }
 
+       if (!lp->segtype)
+               lp->segtype = first_seg(lv)->segtype;
+
        if (lp->merge) {
                if (!lv_is_cow(lv)) {
-                       log_error("Logical volume \"%s\" is not a snapshot",
+                       log_error("\"%s\" is not a mergeable logical volume",
                                  lv->name);
                        return ECMD_FAILED;
                }
+               if (lv_info(lv->vg->cmd, lv, 0, &info, 1, 0)
+                   && info.exists && info.live_table &&
+                   (!lv_snapshot_percent(lv, &snap_percent) ||
+                    snap_percent == PERCENT_INVALID)) {
+                       log_error("Unable to merge invalidated snapshot LV \"%s\"", lv->name);
+                       return ECMD_FAILED;
+               }
                if (!archive(lv->vg)) {
                        stack;
                        return ECMD_FAILED;
@@ -1589,6 +2026,34 @@ static int _lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
                        stack;
                        return ECMD_FAILED;
                }
+       } else if (arg_count(cmd, thinpool_ARG)) {
+               if (!archive(lv->vg)) {
+                       stack;
+                       return ECMD_FAILED;
+               }
+               if (!_lvconvert_thinpool(cmd, lv, lp)) {
+                       stack;
+                       return ECMD_FAILED;
+               }
+       } else if (segtype_is_raid(lp->segtype) ||
+                  (lv->status & RAID) || lp->merge_mirror) {
+               if (!archive(lv->vg)) {
+                       stack;
+                       return ECMD_FAILED;
+               }
+               if (!lvconvert_raid(lv, lp)) {
+                       stack;
+                       return ECMD_FAILED;
+               }
+
+               if (!(failed_pvs = _failed_pv_list(lv->vg))) {
+                       stack;
+                       return ECMD_FAILED;
+               }
+
+               /* If repairing and using policies, remove missing PVs from VG */
+               if (arg_count(cmd, repair_ARG) && arg_count(cmd, use_policies_ARG))
+                       _remove_missing_empty_pv(lv->vg, failed_pvs);
        } else if (arg_count(cmd, mirrors_ARG) ||
                   arg_count(cmd, splitmirrors_ARG) ||
                   (lv->status & MIRRORED)) {
@@ -1601,9 +2066,14 @@ static int _lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
                        return ECMD_FAILED;
                }
 
+               if (!(failed_pvs = _failed_pv_list(lv->vg))) {
+                       stack;
+                       return ECMD_FAILED;
+               }
+
                /* If repairing and using policies, remove missing PVs from VG */
                if (arg_count(cmd, repair_ARG) && arg_count(cmd, use_policies_ARG))
-                       _remove_missing_empty_pv(lv->vg, lp->failed_pvs);
+                       _remove_missing_empty_pv(lv->vg, failed_pvs);
        }
 
        return ECMD_PROCESSED;
@@ -1619,7 +2089,7 @@ static struct logical_volume *get_vg_lock_and_logical_volume(struct cmd_context
 {
        /*
         * Returns NULL if the requested LV doesn't exist;
-        * otherwise the caller must free_vg(lv->vg)
+        * otherwise the caller must release_vg(lv->vg)
         * - it is also up to the caller to unlock_vg() as needed
         */
        struct volume_group *vg;
@@ -1627,13 +2097,13 @@ static struct logical_volume *get_vg_lock_and_logical_volume(struct cmd_context
 
        vg = _get_lvconvert_vg(cmd, vg_name, NULL);
        if (vg_read_error(vg)) {
-               free_vg(vg);
+               release_vg(vg);
                return_NULL;
        }
 
        if (!(lv = _get_lvconvert_lv(cmd, vg, lv_name, NULL, 0))) {
                log_error("Can't find LV %s in VG %s", lv_name, vg_name);
-               unlock_and_free_vg(cmd, vg, vg_name);
+               unlock_and_release_vg(cmd, vg, vg_name);
                return NULL;
        }
 
@@ -1645,8 +2115,8 @@ static int poll_logical_volume(struct cmd_context *cmd, struct logical_volume *l
 {
        struct lvinfo info;
 
-       if (!lv_info(cmd, lv, 0, &info, 1, 0) || !info.exists) {
-               log_print("Conversion starts after activation.");
+       if (!lv_info(cmd, lv, 0, &info, 0, 0) || !info.exists) {
+               log_print_unless_silent("Conversion starts after activation.");
                return ECMD_PROCESSED;
        }
        return lvconvert_poll(cmd, lv, wait_completion ? 0 : 1U);
@@ -1677,6 +2147,12 @@ static int lvconvert_single(struct cmd_context *cmd, struct lvconvert_params *lp
        } else
                lp->pvh = &lv->vg->pvs;
 
+       if (lp->replace_pv_count &&
+           !(lp->replace_pvh = create_pv_list(cmd->mem, lv->vg,
+                                              lp->replace_pv_count,
+                                              lp->replace_pvs, 0)))
+                       goto_bad;
+
        lp->lv_to_poll = lv;
        ret = _lvconvert_single(cmd, lv, lp);
 bad:
@@ -1686,7 +2162,7 @@ bad:
                ret = poll_logical_volume(cmd, lp->lv_to_poll,
                                          lp->wait_completion);
 
-       free_vg(lv->vg);
+       release_vg(lv->vg);
 out:
        init_ignore_suspended_devices(saved_ignore_suspended_devices);
        return ret;
@@ -1736,7 +2212,7 @@ static int lvconvert_merge_single(struct cmd_context *cmd, struct logical_volume
                }
        }
 
-       free_vg(refreshed_lv->vg);
+       release_vg(refreshed_lv->vg);
 
        return ret;
 }
index 13b59265960743180abdd953384b26a25d3ad28e..3ea8f467030bea4875e15ab2e3126a3e60be0f16 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -14,7 +14,6 @@
  */
 
 #include "tools.h"
-#include "lv_alloc.h"
 
 #include <fcntl.h>
 
@@ -25,46 +24,122 @@ struct lvcreate_cmdline_params {
        int pv_count;
 };
 
+static int _set_vg_name(struct lvcreate_params *lp, const char *vg_name)
+{
+       /* Can't do anything */
+       if (!vg_name)
+               return 1;
+
+       /* If VG name already known, ensure this 2nd copy is identical */
+       if (lp->vg_name && strcmp(lp->vg_name, vg_name)) {
+               log_error("Inconsistent volume group names "
+                         "given: \"%s\" and \"%s\"",
+                         lp->vg_name, vg_name);
+               return 0;
+       }
+       lp->vg_name = vg_name;
+
+       return 1;
+}
+
 static int _lvcreate_name_params(struct lvcreate_params *lp,
                                 struct cmd_context *cmd,
                                 int *pargc, char ***pargv)
 {
        int argc = *pargc;
        char **argv = *pargv, *ptr;
-       char *vg_name;
+       const char *vg_name;
+
+       lp->pool = arg_str_value(cmd, thinpool_ARG, NULL);
+
+       /* If --thinpool contains VG name, extract it. */
+       if (lp->pool && strchr(lp->pool, '/')) {
+               if (!(lp->vg_name = extract_vgname(cmd, lp->pool)))
+                       return 0;
+               /* Strip VG from pool */
+               if ((ptr = strrchr(lp->pool, (int) '/')))
+                       lp->pool = ptr + 1;
+       }
 
        lp->lv_name = arg_str_value(cmd, name_ARG, NULL);
 
+       /* If --name contains VG name, extract it. */
+       if (lp->lv_name && strchr(lp->lv_name, '/')) {
+               if (!_set_vg_name(lp, extract_vgname(cmd, lp->lv_name)))
+                       return_0;
+
+               /* Strip VG from lv_name */
+               if ((ptr = strrchr(lp->lv_name, (int) '/')))
+                       lp->lv_name = ptr + 1;
+       }
+
+       /* Need an origin? */
        if (lp->snapshot && !arg_count(cmd, virtualsize_ARG)) {
+               /* argv[0] might be origin or vg/origin */
                if (!argc) {
                        log_error("Please specify a logical volume to act as "
                                  "the snapshot origin.");
                        return 0;
                }
 
-               lp->origin = argv[0];
-               (*pargv)++, (*pargc)--;
-               if (!(lp->vg_name = extract_vgname(cmd, lp->origin))) {
+               lp->origin = skip_dev_dir(cmd, argv[0], NULL);
+               if (strrchr(lp->origin, '/')) {
+                       if (!_set_vg_name(lp, extract_vgname(cmd, lp->origin)))
+                               return_0;
+
+                       /* Strip the volume group from the origin */
+                       if ((ptr = strrchr(lp->origin, (int) '/')))
+                               lp->origin = ptr + 1;
+               }
+
+               if (!lp->vg_name &&
+                   !_set_vg_name(lp, extract_vgname(cmd, NULL)))
+                       return_0;
+
+               if (!lp->vg_name) {
                        log_error("The origin name should include the "
                                  "volume group.");
                        return 0;
                }
 
-               /* Strip the volume group from the origin */
-               if ((ptr = strrchr(lp->origin, (int) '/')))
-                       lp->origin = ptr + 1;
+               (*pargv)++, (*pargc)--;
+       } else if (seg_is_thin(lp) && !lp->pool && argc) {
+               /* argv[0] might be vg or vg/Pool */
+
+               vg_name = skip_dev_dir(cmd, argv[0], NULL);
+               if (!strrchr(vg_name, '/')) {
+                       if (!_set_vg_name(lp, vg_name))
+                               return_0;
+               } else {
+                       lp->pool = vg_name;
+                       if (!_set_vg_name(lp, extract_vgname(cmd, lp->pool)))
+                               return_0;
+
+                       if (!lp->vg_name &&
+                           !_set_vg_name(lp, extract_vgname(cmd, NULL)))
+                               return_0;
+
+                       if (!lp->vg_name) {
+                               log_error("The pool name should include the "
+                                         "volume group.");
+                               return 0;
+                       }
+
+                       /* Strip the volume group */
+                       if ((ptr = strrchr(lp->pool, (int) '/')))
+                               lp->pool = ptr + 1;
+               }
 
+               (*pargv)++, (*pargc)--;
        } else {
                /*
-                * If VG not on command line, try -n arg and then
-                * environment.
+                * If VG not on command line, try environment default.
                 */
                if (!argc) {
-                       if (!(lp->vg_name = extract_vgname(cmd, lp->lv_name))) {
+                       if (!lp->vg_name && !(lp->vg_name = extract_vgname(cmd, NULL))) {
                                log_error("Please provide a volume group name");
                                return 0;
                        }
-
                } else {
                        vg_name = skip_dev_dir(cmd, argv[0], NULL);
                        if (strrchr(vg_name, '/')) {
@@ -73,25 +148,9 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
                                return 0;
                        }
 
-                       /*
-                        * Ensure lv_name doesn't contain a
-                        * different VG.
-                        */
-                       if (lp->lv_name && strchr(lp->lv_name, '/')) {
-                               if (!(lp->vg_name =
-                                     extract_vgname(cmd, lp->lv_name)))
-                                       return 0;
-
-                               if (strcmp(lp->vg_name, vg_name)) {
-                                       log_error("Inconsistent volume group "
-                                                 "names "
-                                                 "given: \"%s\" and \"%s\"",
-                                                 lp->vg_name, vg_name);
-                                       return 0;
-                               }
-                       }
+                       if (!_set_vg_name(lp, vg_name))
+                               return_0;
 
-                       lp->vg_name = vg_name;
                        (*pargv)++, (*pargc)--;
                }
        }
@@ -103,9 +162,6 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
        }
 
        if (lp->lv_name) {
-               if ((ptr = strrchr(lp->lv_name, '/')))
-                       lp->lv_name = ptr + 1;
-
                if (!apply_lvname_restrictions(lp->lv_name))
                        return_0;
 
@@ -116,12 +172,59 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
                }
        }
 
+       if (lp->pool) {
+               if (!apply_lvname_restrictions(lp->pool))
+                       return_0;
+
+               if (!validate_name(lp->pool)) {
+                       log_error("Logical volume name \"%s\" is invalid",
+                                 lp->pool);
+                       return 0;
+               }
+
+               if (lp->lv_name && !strcmp(lp->lv_name, lp->pool)) {
+                       log_error("Logical volume name %s and pool name %s must be different.", 
+                                 lp->lv_name, lp->pool);
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
+/*
+ * Normal snapshot or thinly-provisioned snapshot?
+ */
+static int _determine_snapshot_type(struct volume_group *vg,
+                                 struct lvcreate_params *lp)
+{
+       struct lv_list *lvl;
+
+       if (!(lvl = find_lv_in_vg(vg, lp->origin))) {
+               log_error("Snapshot origin LV %s not found in Volume group %s.",
+                         lp->origin, vg->name);
+               return 0;
+       }
+
+       if (!arg_count(vg->cmd, extents_ARG) && !arg_count(vg->cmd, size_ARG)) {
+               if (!lv_is_thin_volume(lvl->lv)) {
+                       log_error("Please specify either size or extents with snapshots.");
+                       return 0;
+               }
+
+               lp->thin = 1;
+               if (!(lp->segtype = get_segtype_from_string(vg->cmd, "thin")))
+                       return_0;
+
+               lp->pool = first_seg(lvl->lv)->pool_lv->name;
+       }
+
        return 1;
 }
 
 /*
  * Update extents parameters based on other parameters which affect the size
- * calcuation.
+ * calculation.
  * NOTE: We must do this here because of the percent_t typedef and because we
  * need the vg.
  */
@@ -131,6 +234,9 @@ static int _update_extents_params(struct volume_group *vg,
 {
        uint32_t pv_extent_count;
        struct logical_volume *origin = NULL;
+       int changed = 0;
+       uint32_t size_rest;
+       uint32_t stripesize_extents;
 
        if (lcp->size &&
            !(lp->extents = extents_from_size(vg->cmd, lcp->size,
@@ -155,17 +261,17 @@ static int _update_extents_params(struct volume_group *vg,
 
        switch(lcp->percent) {
                case PERCENT_VG:
-                       lp->extents = lp->extents * vg->extent_count / 100;
+                       lp->extents = percent_of_extents(lp->extents, vg->extent_count, 0);
                        break;
                case PERCENT_FREE:
-                       lp->extents = lp->extents * vg->free_count / 100;
+                       lp->extents = percent_of_extents(lp->extents, vg->free_count, 0);
                        break;
                case PERCENT_PVS:
                        if (!lcp->pv_count)
-                               lp->extents = lp->extents * vg->extent_count / 100;
+                               lp->extents = percent_of_extents(lp->extents, vg->extent_count, 0);
                        else {
                                pv_extent_count = pv_list_extents_free(lp->pvh);
-                               lp->extents = lp->extents * pv_extent_count / 100;
+                               lp->extents = percent_of_extents(lp->extents, pv_extent_count, 0);
                        }
                        break;
                case PERCENT_LV:
@@ -183,11 +289,63 @@ static int _update_extents_params(struct volume_group *vg,
                                log_error(INTERNAL_ERROR "Couldn't find origin volume.");
                                return 0;
                        }
-                       lp->extents = lp->extents * origin->le_count / 100;
+                       lp->extents = percent_of_extents(lp->extents, origin->le_count, 0);
                        break;
                case PERCENT_NONE:
                        break;
        }
+
+       if (!(stripesize_extents = lp->stripe_size / vg->extent_size))
+               stripesize_extents = 1;
+
+       if ((lcp->percent != PERCENT_NONE) && lp->stripes &&
+           (size_rest = lp->extents % (lp->stripes * stripesize_extents)) &&
+           (vg->free_count < lp->extents - size_rest + (lp->stripes * stripesize_extents))) {
+               log_print_unless_silent("Rounding size (%d extents) down to stripe boundary "
+                                       "size (%d extents)", lp->extents,
+                         lp->extents - size_rest);
+               lp->extents = lp->extents - size_rest;
+       }
+
+       if (lp->create_thin_pool) {
+               if (!arg_count(vg->cmd, poolmetadatasize_ARG)) {
+                       /* Defaults to nr_pool_blocks * 64b */
+                       lp->poolmetadatasize =  (uint64_t) lp->extents * vg->extent_size /
+                               (uint64_t) (lp->chunk_size * (SECTOR_SIZE / UINT64_C(64)));
+
+                       /* Check if we could eventually use bigger chunk size */
+                       if (!arg_count(vg->cmd, chunksize_ARG)) {
+                               while ((lp->poolmetadatasize >
+                                       (DEFAULT_THIN_POOL_OPTIMAL_SIZE / SECTOR_SIZE)) &&
+                                      (lp->chunk_size < DM_THIN_MAX_DATA_BLOCK_SIZE)) {
+                                       lp->chunk_size <<= 1;
+                                       lp->poolmetadatasize >>= 1;
+                                       changed++;
+                               }
+                               if (changed)
+                                       log_verbose("Changed chunksize to %u sectors.",
+                                                   lp->chunk_size);
+                       }
+               }
+
+               if (lp->poolmetadatasize > (2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE)) {
+                       if (arg_count(vg->cmd, poolmetadatasize_ARG))
+                               log_warn("WARNING: Maximum supported pool metadata size is 16GB.");
+                       lp->poolmetadatasize = 2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE;
+               } else if (lp->poolmetadatasize < (2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE)) {
+                       if (arg_count(vg->cmd, poolmetadatasize_ARG))
+                               log_warn("WARNING: Minimum supported pool metadata size is 2M.");
+                       lp->poolmetadatasize = 2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE;
+               }
+
+               log_verbose("Setting pool metadata size to %" PRIu64 " sectors.",
+                           lp->poolmetadatasize);
+
+               if (!(lp->poolmetadataextents =
+                     extents_from_size(vg->cmd, lp->poolmetadatasize, vg->extent_size)))
+                       return_0;
+       }
+
        return 1;
 }
 
@@ -195,13 +353,18 @@ static int _read_size_params(struct lvcreate_params *lp,
                             struct lvcreate_cmdline_params *lcp,
                             struct cmd_context *cmd)
 {
-       if (arg_count(cmd, extents_ARG) + arg_count(cmd, size_ARG) != 1) {
+       if (arg_count(cmd, extents_ARG) && arg_count(cmd, size_ARG)) {
                log_error("Please specify either size or extents (not both)");
                return 0;
        }
 
+       if (!lp->thin && !lp->snapshot && !arg_count(cmd, extents_ARG) && !arg_count(cmd, size_ARG)) {
+               log_error("Please specify either size or extents");
+               return 0;
+       }
+
        if (arg_count(cmd, extents_ARG)) {
-               if (arg_sign_value(cmd, extents_ARG, 0) == SIGN_MINUS) {
+               if (arg_sign_value(cmd, extents_ARG, SIGN_NONE) == SIGN_MINUS) {
                        log_error("Negative number of extents is invalid");
                        return 0;
                }
@@ -211,7 +374,7 @@ static int _read_size_params(struct lvcreate_params *lp,
 
        /* Size returned in kilobyte units; held in sectors */
        if (arg_count(cmd, size_ARG)) {
-               if (arg_sign_value(cmd, size_ARG, 0) == SIGN_MINUS) {
+               if (arg_sign_value(cmd, size_ARG, SIGN_NONE) == SIGN_MINUS) {
                        log_error("Negative size is invalid");
                        return 0;
                }
@@ -219,9 +382,29 @@ static int _read_size_params(struct lvcreate_params *lp,
                lcp->percent = PERCENT_NONE;
        }
 
+       /* If size/extents given with thin, then we are creating a thin pool */
+       if (lp->thin && (arg_count(cmd, size_ARG) || arg_count(cmd, extents_ARG)))
+               lp->create_thin_pool = 1;
+
+       if (arg_count(cmd, poolmetadatasize_ARG)) {
+               if (!seg_is_thin(lp)) {
+                       log_error("--poolmetadatasize may only be specified when allocating the thin pool.");
+                       return 0;
+               }
+               if (arg_sign_value(cmd, poolmetadatasize_ARG, SIGN_NONE) == SIGN_MINUS) {
+                       log_error("Negative poolmetadatasize is invalid.");
+                       return 0;
+               }
+               lp->poolmetadatasize = arg_uint64_value(cmd, poolmetadatasize_ARG, UINT64_C(0));
+       }
+
        /* Size returned in kilobyte units; held in sectors */
        if (arg_count(cmd, virtualsize_ARG)) {
-               if (arg_sign_value(cmd, virtualsize_ARG, 0) == SIGN_MINUS) {
+               if (seg_is_thin_pool(lp)) {
+                       log_error("Virtual size in incompatible with thin_pool segment type.");
+                       return 0;
+               }
+               if (arg_sign_value(cmd, virtualsize_ARG, SIGN_NONE) == SIGN_MINUS) {
                        log_error("Negative virtual origin size is invalid");
                        return 0;
                }
@@ -231,6 +414,12 @@ static int _read_size_params(struct lvcreate_params *lp,
                        log_error("Virtual origin size may not be zero");
                        return 0;
                }
+       } else {
+               /* No virtual size given, so no thin LV to create. */
+               if (seg_is_thin_volume(lp) && !(lp->segtype = get_segtype_from_string(cmd, "thin-pool")))
+                       return_0;
+
+               lp->thin = 0;
        }
 
        return 1;
@@ -297,7 +486,7 @@ static int _read_mirror_params(struct lvcreate_params *lp,
        lp->nosync = arg_is_set(cmd, nosync_ARG);
 
        if (arg_count(cmd, regionsize_ARG)) {
-               if (arg_sign_value(cmd, regionsize_ARG, 0) == SIGN_MINUS) {
+               if (arg_sign_value(cmd, regionsize_ARG, SIGN_NONE) == SIGN_MINUS) {
                        log_error("Negative regionsize is invalid");
                        return 0;
                }
@@ -320,15 +509,177 @@ static int _read_mirror_params(struct lvcreate_params *lp,
        return 1;
 }
 
+static int _read_raid_params(struct lvcreate_params *lp,
+                            struct cmd_context *cmd)
+{
+       if (!segtype_is_raid(lp->segtype))
+               return 1;
+
+       if (arg_count(cmd, corelog_ARG) ||
+           arg_count(cmd, mirrorlog_ARG)) {
+               log_error("Log options not applicable to %s segtype",
+                         lp->segtype->name);
+               return 0;
+       }
+
+       /*
+        * get_stripe_params is called before _read_raid_params
+        * and already sets:
+        *   lp->stripes
+        *   lp->stripe_size
+        *
+        * For RAID 4/5/6, these values must be set.
+        */
+       if (!segtype_is_mirrored(lp->segtype) &&
+           (lp->stripes <= lp->segtype->parity_devs)) {
+               log_error("Number of stripes must be at least %d for %s",
+                         lp->segtype->parity_devs + 1, lp->segtype->name);
+               return 0;
+       }
+
+       /*
+        * RAID types without a mirror component do not take '-m' arg
+        */
+       if (!segtype_is_mirrored(lp->segtype) &&
+           arg_count(cmd, mirrors_ARG)) {
+               log_error("Mirror argument cannot be used with segment type, %s",
+                         lp->segtype->name);
+               return 0;
+       }
+
+       /*
+        * RAID1 does not take a stripe arg
+        */
+       if ((lp->stripes > 1) &&
+           segtype_is_mirrored(lp->segtype) &&
+           strcmp(lp->segtype->name, "raid10")) {
+               log_error("Stripe argument cannot be used with segment type, %s",
+                         lp->segtype->name);
+               return 0;
+       }
+
+       /*
+        * _read_mirror_params is called before _read_raid_params
+        * and already sets:
+        *   lp->nosync
+        *   lp->region_size
+        *
+        * But let's ensure that programmers don't reorder
+        * that by checking and warning if they aren't set.
+        */
+       if (!lp->region_size) {
+               log_error(INTERNAL_ERROR "region_size not set.");
+               return 0;
+       }
+
+       return 1;
+}
+
+static int _read_activation_params(struct lvcreate_params *lp, struct cmd_context *cmd,
+                                  struct volume_group *vg)
+{
+       unsigned pagesize;
+
+       lp->activate = (activation_change_t)
+               arg_uint_value(cmd, activate_ARG, CHANGE_AY);
+
+       if (lp->activate == CHANGE_AN || lp->activate == CHANGE_ALN) {
+               if (lp->zero && !seg_is_thin(lp)) {
+                       log_error("--activate n requires --zero n");
+                       return 0;
+               }
+       } else if (lp->activate == CHANGE_AAY) {
+               if (arg_count(cmd, zero_ARG)) {
+                       log_error("-Z is incompatible with --activate a");
+                       return 0;
+               }
+               lp->zero = 0;
+       }
+
+       /*
+        * Read ahead.
+        */
+       lp->read_ahead = arg_uint_value(cmd, readahead_ARG,
+                                       cmd->default_settings.read_ahead);
+       pagesize = lvm_getpagesize() >> SECTOR_SHIFT;
+       if (lp->read_ahead != DM_READ_AHEAD_AUTO &&
+           lp->read_ahead != DM_READ_AHEAD_NONE &&
+           lp->read_ahead % pagesize) {
+               if (lp->read_ahead < pagesize)
+                       lp->read_ahead = pagesize;
+               else
+                       lp->read_ahead = (lp->read_ahead / pagesize) * pagesize;
+               log_warn("WARNING: Overriding readahead to %u sectors, a multiple "
+                           "of %uK page size.", lp->read_ahead, pagesize >> 1);
+       }
+
+       /*
+        * Permissions.
+        */
+       lp->permission = arg_uint_value(cmd, permission_ARG,
+                                       LVM_READ | LVM_WRITE);
+
+       /* Must not zero read only volume */
+       if (!(lp->permission & LVM_WRITE))
+               lp->zero = 0;
+
+       if (arg_count(cmd, major_ARG) > 1) {
+               log_error("Option -j/--major may not be repeated.");
+               return 0;
+       }
+
+       if (arg_count(cmd, minor_ARG) > 1) {
+               log_error("Option --minor may not be repeated.");
+               return 0;
+       }
+
+       lp->minor = arg_int_value(cmd, minor_ARG, -1);
+       lp->major = arg_int_value(cmd, major_ARG, -1);
+
+       /* Persistent minor */
+       if (arg_count(cmd, persistent_ARG)) {
+               if (lp->create_thin_pool && !lp->thin) {
+                       log_error("--persistent is not permitted when creating a thin pool device.");
+                       return 0;
+               }
+               if (!strcmp(arg_str_value(cmd, persistent_ARG, "n"), "y")) {
+                       if (lp->minor == -1) {
+                               log_error("Please specify minor number with "
+                                         "--minor when using -My");
+                               return 0;
+                       }
+                       if (lp->major == -1) {
+                               log_error("Please specify major number with "
+                                         "--major when using -My");
+                               return 0;
+                       }
+                       if (!major_minor_valid(cmd, vg->fid->fmt, lp->major, lp->minor))
+                               return 0;
+               } else {
+                       if ((lp->minor != -1) || (lp->major != -1)) {
+                               log_error("--major and --minor incompatible "
+                                         "with -Mn");
+                               return 0;
+                       }
+               }
+       } else if (arg_count(cmd, minor_ARG) || arg_count(cmd, major_ARG)) {
+               log_error("--major and --minor require -My");
+               return 0;
+       }
+
+       return 1;
+}
+
 static int _lvcreate_params(struct lvcreate_params *lp,
                            struct lvcreate_cmdline_params *lcp,
                            struct cmd_context *cmd,
                            int argc, char **argv)
 {
        int contiguous;
-       unsigned pagesize;
        struct arg_value_group_list *current_group;
+       const char *segtype_str;
        const char *tag;
+       unsigned attr = 0;
 
        memset(lp, 0, sizeof(*lp));
        memset(lcp, 0, sizeof(*lcp));
@@ -337,64 +688,96 @@ static int _lvcreate_params(struct lvcreate_params *lp,
        /*
         * Check selected options are compatible and determine segtype
         */
-       lp->segtype = get_segtype_from_string(cmd, arg_str_value(cmd, type_ARG, "striped"));
+// FIXME -m0 implies *striped*
+       if ((arg_count(cmd, thin_ARG) || arg_count(cmd, thinpool_ARG)) &&
+           arg_count(cmd,mirrors_ARG)) {
+               log_error("--thin,--thinpool  and --mirrors are incompatible.");
+               return 0;
+       }
+
+// FIXME -m0 implies *striped*
+
+       /* Set default segtype */
+       if (arg_count(cmd, mirrors_ARG))
+               /*
+                * FIXME: Add default setting for when -i and -m arguments
+                *        are both given.  We should default to "raid10".
+                */
+               segtype_str = find_config_tree_str(cmd, "global/mirror_segtype_default", DEFAULT_MIRROR_SEGTYPE);
+       else if (arg_count(cmd, thin_ARG) || arg_count(cmd, thinpool_ARG))
+               segtype_str = "thin";
+       else
+               segtype_str = "striped";
+
+       segtype_str = arg_str_value(cmd, type_ARG, segtype_str);
+
+       if (!(lp->segtype = get_segtype_from_string(cmd, segtype_str)))
+               return_0;
+
+       if (seg_unknown(lp)) {
+               log_error("Unable to create LV with unknown segment type %s.", segtype_str);
+               return 0;
+       }
 
        if (arg_count(cmd, snapshot_ARG) || seg_is_snapshot(lp) ||
-           arg_count(cmd, virtualsize_ARG))
+           (!seg_is_thin(lp) && arg_count(cmd, virtualsize_ARG)))
                lp->snapshot = 1;
 
+       if (seg_is_thin_pool(lp)) {
+               if (lp->snapshot) {
+                       log_error("Snapshots are incompatible with thin_pool segment_type.");
+                       return 0;
+               }
+               lp->create_thin_pool = 1;
+       }
+
+       if (seg_is_thin_volume(lp))
+               lp->thin = 1;
+
        lp->mirrors = 1;
 
-       /* Default to 2 mirrored areas if --type mirror */
-       if (seg_is_mirrored(lp))
+       /* Default to 2 mirrored areas if '--type mirror|raid1|raid10' */
+       if (segtype_is_mirrored(lp->segtype))
                lp->mirrors = 2;
 
        if (arg_count(cmd, mirrors_ARG)) {
                lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1;
-               if (lp->mirrors == 1)
-                       log_print("Redundant mirrors argument: default is 0");
-               if (arg_sign_value(cmd, mirrors_ARG, 0) == SIGN_MINUS) {
-                       log_error("Mirrors argument may not be negative");
-                       return 0;
+               if (lp->mirrors == 1) {
+                       if (segtype_is_mirrored(lp->segtype)) {
+                               log_error("--mirrors must be at least 1 with segment type %s.", lp->segtype->name);
+                               return 0;
+                       }
+                       log_print_unless_silent("Redundant mirrors argument: default is 0");
                }
-       }
 
-       if (lp->snapshot) {
-               if (arg_count(cmd, zero_ARG)) {
-                       log_error("-Z is incompatible with snapshots");
-                       return 0;
-               }
-               if (arg_sign_value(cmd, chunksize_ARG, 0) == SIGN_MINUS) {
-                       log_error("Negative chunk size is invalid");
-                       return 0;
-               }
-               lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, 8);
-               if (lp->chunk_size < 8 || lp->chunk_size > 1024 ||
-                   (lp->chunk_size & (lp->chunk_size - 1))) {
-                       log_error("Chunk size must be a power of 2 in the "
-                                 "range 4K to 512K");
+               if ((lp->mirrors > 2) && !strcmp(lp->segtype->name, "raid10")) {
+                       /*
+                        * FIXME: When RAID10 is no longer limited to
+                        *        2-way mirror, 'lv_mirror_count()'
+                        *        must also change for RAID10.
+                        */
+                       log_error("RAID10 currently supports "
+                                 "only 2-way mirroring (i.e. '-m 1')");
                        return 0;
                }
-               log_verbose("Setting chunksize to %d sectors.", lp->chunk_size);
 
-               if (!(lp->segtype = get_segtype_from_string(cmd, "snapshot")))
-                       return_0;
-       } else {
-               if (arg_count(cmd, chunksize_ARG)) {
-                       log_error("-c is only available with snapshots");
+               if (arg_sign_value(cmd, mirrors_ARG, SIGN_NONE) == SIGN_MINUS) {
+                       log_error("Mirrors argument may not be negative");
                        return 0;
                }
        }
 
-       if (lp->mirrors > 1) {
+       if (lp->snapshot && arg_count(cmd, zero_ARG)) {
+               log_error("-Z is incompatible with snapshots");
+               return 0;
+       }
+
+       if (segtype_is_mirrored(lp->segtype) || segtype_is_raid(lp->segtype)) {
                if (lp->snapshot) {
                        log_error("mirrors and snapshots are currently "
                                  "incompatible");
                        return 0;
                }
-
-               if (!(lp->segtype = get_segtype_from_string(cmd, "striped")))
-                       return_0;
        } else {
                if (arg_count(cmd, corelog_ARG)) {
                        log_error("--corelog is only available with mirrors");
@@ -413,42 +796,93 @@ static int _lvcreate_params(struct lvcreate_params *lp,
        }
 
        if (activation() && lp->segtype->ops->target_present &&
-           !lp->segtype->ops->target_present(cmd, NULL, NULL)) {
+           !lp->segtype->ops->target_present(cmd, NULL, &attr)) {
                log_error("%s: Required device-mapper target(s) not "
                          "detected in your kernel", lp->segtype->name);
                return 0;
+       } else if (!strcmp(lp->segtype->name, "raid10")) {
+               uint32_t maj, min, patchlevel;
+               if (!target_version("raid", &maj, &min, &patchlevel)) {
+                       log_error("Failed to determine version of RAID kernel module");
+                       return 0;
+               }
+               if ((maj != 1) || (min < 3)) {
+                       log_error("RAID module does not support RAID10");
+                       return 0;
+               }
        }
 
-       if (!get_activation_monitoring_mode(cmd, NULL,
-                                           &lp->activation_monitoring))
-               return_0;
-
        if (!_lvcreate_name_params(lp, cmd, &argc, &argv) ||
            !_read_size_params(lp, lcp, cmd) ||
            !get_stripe_params(cmd, &lp->stripes, &lp->stripe_size) ||
-           !_read_mirror_params(lp, cmd))
+           !_read_mirror_params(lp, cmd) ||
+           !_read_raid_params(lp, cmd))
                return_0;
 
+       if (lp->create_thin_pool)
+               lp->discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_PASSDOWN);
+       else if (arg_count(cmd, discards_ARG)) {
+               log_error("--discards is only available for thin pool creation.");
+               return 0;
+       }
+
+       if (lp->snapshot && lp->thin && arg_count(cmd, chunksize_ARG))
+               log_warn("WARNING: Ignoring --chunksize with thin snapshots.");
+       else if (lp->thin && !lp->create_thin_pool) {
+               if (arg_count(cmd, chunksize_ARG))
+                       log_warn("WARNING: Ignoring --chunksize when using an existing pool.");
+       } else if (lp->snapshot || lp->create_thin_pool) {
+               if (arg_sign_value(cmd, chunksize_ARG, SIGN_NONE) == SIGN_MINUS) {
+                       log_error("Negative chunk size is invalid");
+                       return 0;
+               }
+               if (lp->snapshot) {
+                       lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, 8);
+                       if (lp->chunk_size < 8 || lp->chunk_size > 1024 ||
+                           (lp->chunk_size & (lp->chunk_size - 1))) {
+                               log_error("Chunk size must be a power of 2 in the "
+                                         "range 4K to 512K");
+                               return 0;
+                       }
+               } else {
+                       lp->chunk_size = arg_uint_value(cmd, chunksize_ARG,
+                                                       DM_THIN_MIN_DATA_BLOCK_SIZE);
+                       if ((lp->chunk_size < DM_THIN_MIN_DATA_BLOCK_SIZE) ||
+                           (lp->chunk_size > DM_THIN_MAX_DATA_BLOCK_SIZE)) {
+                               log_error("Chunk size must be in the range %uK to %uK",
+                                         (DM_THIN_MIN_DATA_BLOCK_SIZE / 2),
+                                         (DM_THIN_MAX_DATA_BLOCK_SIZE / 2));
+                               return 0;
+                       }
+                       if (!(attr & THIN_FEATURE_BLOCK_SIZE) &&
+                           (lp->chunk_size & (lp->chunk_size - 1))) {
+                               log_error("Chunk size must be a power of 2 for this thin target version.");
+                               return 0;
+                       } else if (lp->chunk_size & (DM_THIN_MIN_DATA_BLOCK_SIZE - 1)) {
+                               log_error("Chunk size must be multiple of %uK.",
+                                         DM_THIN_MIN_DATA_BLOCK_SIZE / 2);
+                               return 0;
+                       } else if ((lp->discards != THIN_DISCARDS_IGNORE) &&
+                                  (lp->chunk_size & (lp->chunk_size - 1))) {
+                               log_warn("WARNING: Using discards ignore for chunk size non power of 2.");
+                               lp->discards = THIN_DISCARDS_IGNORE;
+                       }
+               }
+               log_verbose("Setting chunksize to %u sectors.", lp->chunk_size);
+
+               if (!lp->thin && lp->snapshot && !(lp->segtype = get_segtype_from_string(cmd, "snapshot")))
+                       return_0;
+       } else if (arg_count(cmd, chunksize_ARG)) {
+               log_error("-c is only available with snapshots and thin pools");
+               return 0;
+       }
+
        /*
         * Should we zero the lv.
         */
        lp->zero = strcmp(arg_str_value(cmd, zero_ARG,
                (lp->segtype->flags & SEG_CANNOT_BE_ZEROED) ? "n" : "y"), "n");
 
-       /*
-        * Alloc policy
-        */
-       contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n");
-
-       lp->alloc = contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT;
-
-       lp->alloc = arg_uint_value(cmd, alloc_ARG, lp->alloc);
-
-       if (contiguous && (lp->alloc != ALLOC_CONTIGUOUS)) {
-               log_error("Conflicting contiguous and alloc arguments");
-               return 0;
-       }
-
        if (lp->mirrors > DEFAULT_MIRROR_MAX_IMAGES) {
                log_error("Only up to %d images in mirror supported currently.",
                          DEFAULT_MIRROR_MAX_IMAGES);
@@ -456,57 +890,16 @@ static int _lvcreate_params(struct lvcreate_params *lp,
        }
 
        /*
-        * Read ahead.
+        * Allocation parameters
         */
-       lp->read_ahead = arg_uint_value(cmd, readahead_ARG,
-                                       cmd->default_settings.read_ahead);
-       pagesize = lvm_getpagesize() >> SECTOR_SHIFT;
-       if (lp->read_ahead != DM_READ_AHEAD_AUTO &&
-           lp->read_ahead != DM_READ_AHEAD_NONE &&
-           lp->read_ahead % pagesize) {
-               if (lp->read_ahead < pagesize)
-                       lp->read_ahead = pagesize;
-               else
-                       lp->read_ahead = (lp->read_ahead / pagesize) * pagesize;
-               log_warn("WARNING: Overriding readahead to %u sectors, a multiple "
-                           "of %uK page size.", lp->read_ahead, pagesize >> 1);
-       }
-
-       /*
-        * Permissions.
-        */
-       lp->permission = arg_uint_value(cmd, permission_ARG,
-                                       LVM_READ | LVM_WRITE);
+       contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n");
 
-       /* Must not zero read only volume */
-       if (!(lp->permission & LVM_WRITE))
-               lp->zero = 0;
+       lp->alloc = contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT;
 
-       lp->minor = arg_int_value(cmd, minor_ARG, -1);
-       lp->major = arg_int_value(cmd, major_ARG, -1);
+       lp->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, lp->alloc);
 
-       /* Persistent minor */
-       if (arg_count(cmd, persistent_ARG)) {
-               if (!strcmp(arg_str_value(cmd, persistent_ARG, "n"), "y")) {
-                       if (lp->minor == -1) {
-                               log_error("Please specify minor number with "
-                                         "--minor when using -My");
-                               return 0;
-                       }
-                       if (lp->major == -1) {
-                               log_error("Please specify major number with "
-                                         "--major when using -My");
-                               return 0;
-                       }
-               } else {
-                       if ((lp->minor != -1) || (lp->major != -1)) {
-                               log_error("--major and --minor incompatible "
-                                         "with -Mn");
-                               return 0;
-                       }
-               }
-       } else if (arg_count(cmd, minor_ARG) || arg_count(cmd, major_ARG)) {
-               log_error("--major and --minor require -My");
+       if (contiguous && (lp->alloc != ALLOC_CONTIGUOUS)) {
+               log_error("Conflicting contiguous and alloc arguments");
                return 0;
        }
 
@@ -520,10 +913,10 @@ static int _lvcreate_params(struct lvcreate_params *lp,
                }
 
                if (!str_list_add(cmd->mem, &lp->tags, tag)) {
-                       log_error("Unable to allocate memory for tag %s", tag);
+                       log_error("Unable to allocate memory for tag %s", tag);
                        return 0;
                }
-        }
+       }
 
        lcp->pv_count = argc;
        lcp->pvs = argv;
@@ -531,6 +924,144 @@ static int _lvcreate_params(struct lvcreate_params *lp,
        return 1;
 }
 
+static int _check_thin_parameters(struct volume_group *vg, struct lvcreate_params *lp,
+                                 struct lvcreate_cmdline_params *lcp)
+{
+       struct lv_list *lvl;
+
+       if (!lp->thin && !lp->create_thin_pool) {
+               log_error("Please specify device size(s).");
+               return 0;
+       }
+
+       if (lp->thin && !lp->create_thin_pool) {
+               if (arg_count(vg->cmd, chunksize_ARG)) {
+                       log_error("Only specify --chunksize when originally creating the thin pool.");
+                       return 0;
+               }
+
+               if (lcp->pv_count) {
+                       log_error("Only specify Physical volumes when allocating the thin pool.");
+                       return 0;
+               }
+
+               if (arg_count(vg->cmd, alloc_ARG)) {
+                       log_error("--alloc may only be specified when allocating the thin pool.");
+                       return 0;
+               }
+
+               if (arg_count(vg->cmd, poolmetadatasize_ARG)) {
+                       log_error("--poolmetadatasize may only be specified when allocating the thin pool.");
+                       return 0;
+               }
+
+               if (arg_count(vg->cmd, stripesize_ARG)) {
+                       log_error("--stripesize may only be specified when allocating the thin pool.");
+                       return 0;
+               }
+
+               if (arg_count(vg->cmd, stripes_ARG)) {
+                       log_error("--stripes may only be specified when allocating the thin pool.");
+                       return 0;
+               }
+
+               if (arg_count(vg->cmd, contiguous_ARG)) {
+                       log_error("--contiguous may only be specified when allocating the thin pool.");
+                       return 0;
+               }
+
+               if (arg_count(vg->cmd, zero_ARG)) {
+                       log_error("--zero may only be specified when allocating the thin pool.");
+                       return 0;
+               }
+       }
+
+       if (lp->create_thin_pool && lp->pool) {
+               if (find_lv_in_vg(vg, lp->pool)) {
+                       log_error("Pool %s already exists in Volume group %s.", lp->pool, vg->name);
+                       return 0;
+               }
+       } else if (lp->pool) {
+               if (!(lvl = find_lv_in_vg(vg, lp->pool))) {
+                       log_error("Pool %s not found in Volume group %s.", lp->pool, vg->name);
+                       return 0;
+               }
+               if (!lv_is_thin_pool(lvl->lv)) {
+                       log_error("Logical volume %s is not a thin pool.", lp->pool);
+                       return 0;
+               }
+       } else if (!lp->create_thin_pool) {
+               log_error("Please specify name of existing pool.");
+               return 0;
+       }
+
+       if (!lp->thin && lp->lv_name) {
+               log_error("--name may only be given when creating a new thin Logical volume or snapshot.");
+               return 0;
+       }
+
+       if (!lp->thin) {
+               if (arg_count(vg->cmd, readahead_ARG)) {
+                       log_error("--readhead may only be given when creating a new thin Logical volume or snapshot.");
+                       return 0;
+               }
+               if (arg_count(vg->cmd, permission_ARG)) {
+                       log_error("--permission may only be given when creating a new thin Logical volume or snapshot.");
+                       return 0;
+               }
+               if (arg_count(vg->cmd, persistent_ARG)) {
+                       log_error("--persistent may only be given when creating a new thin Logical volume or snapshot.");
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
+/*
+ * Ensure the set of thin parameters extracted from the command line is consistent.
+ */
+static int _validate_internal_thin_processing(const struct lvcreate_params *lp)
+{
+       int r = 1;
+
+       /*
+          The final state should be one of:
+          thin  create_thin_pool  snapshot   origin   pool  
+            1          1             0          0      y/n    - create new pool and a thin LV in it
+            1          0             0          0      y      - create new thin LV in existing pool
+            0          1             0          0      y/n    - create new pool only
+            1          0             1          1      y      - create thin snapshot of existing thin LV
+       */
+
+       if (!lp->create_thin_pool && !lp->pool) {
+               log_error(INTERNAL_ERROR "--thinpool not identified.");
+               r = 0;
+       }
+
+       if ((lp->snapshot && !lp->origin) || (!lp->snapshot && lp->origin)) {
+               log_error(INTERNAL_ERROR "Inconsistent snapshot and origin parameters identified.");
+               r = 0;
+       }
+
+       if (lp->snapshot && (lp->create_thin_pool || !lp->thin)) {
+               log_error(INTERNAL_ERROR "Inconsistent thin and snapshot parameters identified.");
+               r = 0;
+       }
+
+       if (!lp->thin && !lp->create_thin_pool) {
+               log_error(INTERNAL_ERROR "Failed to identify what type of thin target to use.");
+               r = 0;
+       }
+
+       if (seg_is_thin_pool(lp) && lp->thin) {
+               log_error(INTERNAL_ERROR "Thin volume cannot be created with thin pool segment type.");
+               r = 0;
+       }
+
+       return r;
+}
+
 int lvcreate(struct cmd_context *cmd, int argc, char **argv)
 {
        int r = ECMD_PROCESSED;
@@ -538,29 +1069,62 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv)
        struct lvcreate_cmdline_params lcp;
        struct volume_group *vg;
 
-       memset(&lp, 0, sizeof(lp));
-
        if (!_lvcreate_params(&lp, &lcp, cmd, argc, argv))
                return EINVALID_CMD_LINE;
 
        log_verbose("Finding volume group \"%s\"", lp.vg_name);
        vg = vg_read_for_update(cmd, lp.vg_name, NULL, 0);
        if (vg_read_error(vg)) {
-               free_vg(vg);
+               release_vg(vg);
                stack;
                return ECMD_FAILED;
        }
 
+       if (lp.snapshot && lp.origin && !_determine_snapshot_type(vg, &lp)) {
+               r = ECMD_FAILED;
+               goto_out;
+       }
+
+       if (seg_is_thin(&lp) && !_check_thin_parameters(vg, &lp, &lcp)) {
+               r = ECMD_FAILED;
+               goto_out;
+       }
+
+       /*
+        * Check activation parameters to support inactive thin snapshot creation
+        * FIXME: anything else needs to be moved past _determine_snapshot_type()?
+        */
+       if (!_read_activation_params(&lp, cmd, vg)) {
+               r = ECMD_FAILED;
+               goto_out;
+       }
+
        if (!_update_extents_params(vg, &lp, &lcp)) {
                r = ECMD_FAILED;
                goto_out;
        }
 
+       if (seg_is_thin(&lp) && !_validate_internal_thin_processing(&lp)) {
+               r = ECMD_FAILED;
+               goto_out;
+       }
+
+       if (lp.create_thin_pool)
+               log_verbose("Making thin pool %s in VG %s using segtype %s",
+                           lp.pool ? : "with generated name", lp.vg_name, lp.segtype->name);
+
+       if (lp.thin)
+               log_verbose("Making thin LV %s in pool %s in VG %s%s%s using segtype %s",
+                           lp.lv_name ? : "with generated name",
+                           lp.pool ? : "with generated name", lp.vg_name,
+                           lp.snapshot ? " as snapshot of " : "",
+                           lp.snapshot ? lp.origin : "", lp.segtype->name);
+
        if (!lv_create_single(vg, &lp)) {
                stack;
                r = ECMD_FAILED;
        }
 out:
-       unlock_and_free_vg(cmd, vg, lp.vg_name);
+       unlock_and_release_vg(cmd, vg, lp.vg_name);
        return r;
 }
index cec9f806007179176f83b280ee6df204af0dc22f..425549adc4cfe4ce182a2791018ff7e3d233f1a7 100644 (file)
@@ -60,7 +60,7 @@ static char *_list_args(const char *text, int state)
        /* Initialise if this is a new completion attempt */
        if (!state) {
                char *s = rl_line_buffer;
-               int j = 0;
+               int j;
 
                match_no = 0;
                com = NULL;
@@ -167,7 +167,6 @@ static void _read_history(struct cmd_context *cmd)
 
        stifle_history(find_config_tree_int(cmd, "shell/history_size",
                                       DEFAULT_MAX_HISTORY));
-
 }
 
 static void _write_history(void)
@@ -200,6 +199,7 @@ int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
 
                /* EOF */
                if (!input) {
+                       /* readline sends prompt to stdout */
                        printf("\n");
                        break;
                }
index 66651d89bf13b17eebe42147315de065255a00f7..bf93787a49fabf50b7c9922fdf0de33796e80969 100644 (file)
@@ -51,6 +51,12 @@ void lvm2_log_fn(lvm2_log_fn_t log_fn);
  */ 
 void *lvm2_init(void);
 
+/*
+ * Disable any dmeventd calls that the library may otherwise do. Useful to avoid
+ * recursive calls from dmeventd to itself.
+ */
+void lvm2_disable_dmeventd_monitoring(void *handle);
+
 /*
  * Set log level (as above) if using built-in logging function. 
  * Default is LVM2_LOG_PRINT.  Use LVM2_LOG_SUPPRESS to suppress output.
index 6b2bc9d10b30694e0bb480ec101837ccb362d2e9..6b641c2394075fe0d1a1a09d42c61a2ca8c966d4 100644 (file)
 #include "lvm2cmdline.h"
 #include "label.h"
 #include "memlock.h"
-#include "lvm-version.h"
 
 #include "lvm2cmd.h"
 
 #include <signal.h>
-#include <syslog.h>
-#include <libgen.h>
 #include <sys/stat.h>
 #include <time.h>
 #include <sys/resource.h>
@@ -97,6 +94,10 @@ int lvm2_run(void *handle, const char *cmdline)
        return ret;
 }
 
+void lvm2_disable_dmeventd_monitoring(void *handle) {
+       init_dmeventd_monitor(DMEVENTD_MONITOR_IGNORE);
+}
+
 void lvm2_log_level(void *handle, int level)
 {
        struct cmd_context *cmd = (struct cmd_context *) handle;
index 836dbaa5a92ce3db24d50dd86941fe7d034031b0..39a8c581298caeac352e9d91ea4c32ad06e74fa6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
 #include "lvm-version.h"
 
 #include "stub.h"
-#include "lvm2cmd.h"
 #include "last-path-component.h"
 
 #include <signal.h>
-#include <syslog.h>
-#include <libgen.h>
 #include <sys/stat.h>
 #include <time.h>
 #include <sys/resource.h>
+#include <dirent.h>
+#include <paths.h>
 
 #ifdef HAVE_GETOPTLONG
 #  include <getopt.h>
@@ -42,11 +41,6 @@ extern char *optarg;
 #  define OPTIND_INIT 1
 #endif
 
-#ifdef UDEV_SYNC_SUPPORT
-#  define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
-#  include <libudev.h>
-#endif
-
 /*
  * Table of valid switches
  */
@@ -94,9 +88,29 @@ const char *grouped_arg_str_value(const struct arg_values *av, int a, const char
        return grouped_arg_count(av, a) ? av[a].value : def;
 }
 
+int32_t grouped_arg_int_value(const struct arg_values *av, int a, const int32_t def)
+{
+       return grouped_arg_count(av, a) ? av[a].i_value : def;
+}
+
+int32_t first_grouped_arg_int_value(struct cmd_context *cmd, int a, const int32_t def)
+{
+       struct arg_value_group_list *current_group;
+       struct arg_values *av;
+
+       dm_list_iterate_items(current_group, &cmd->arg_value_groups) {
+               av = current_group->arg_values;
+               if (grouped_arg_count(av, a))
+                       return grouped_arg_int_value(av, a, def);
+       }
+
+       return def;
+}
+
 int32_t arg_int_value(struct cmd_context *cmd, int a, const int32_t def)
 {
-       return arg_count(cmd, a) ? cmd->arg_values[a].i_value : def;
+       return (_cmdline.arg_props[a].flags & ARG_GROUPABLE) ?
+               first_grouped_arg_int_value(cmd, a, def) : (arg_count(cmd, a) ? cmd->arg_values[a].i_value : def);
 }
 
 uint32_t arg_uint_value(struct cmd_context *cmd, int a, const uint32_t def)
@@ -157,7 +171,7 @@ int yes_no_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_value
        return 1;
 }
 
-int yes_no_excl_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av)
+int activation_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av)
 {
        av->sign = SIGN_NONE;
        av->percent = PERCENT_NONE;
@@ -173,6 +187,12 @@ int yes_no_excl_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_
                av->ui_value = CHANGE_AY;
        }
 
+       else if (!strcmp(av->value, "a") || !strcmp(av->value, "ay") ||
+                !strcmp(av->value, "ya")) {
+               av->i_value = CHANGE_AAY;
+               av->ui_value = CHANGE_AAY;
+       }
+
        else if (!strcmp(av->value, "n") || !strcmp(av->value, "en") ||
                 !strcmp(av->value, "ne")) {
                av->i_value = CHANGE_AN;
@@ -195,6 +215,19 @@ int yes_no_excl_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_
        return 1;
 }
 
+int discards_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av)
+{
+       thin_discards_t discards;
+
+       if (!get_pool_discards(av->value, &discards))
+               return_0;
+
+       av->i_value = discards;
+       av->ui_value = discards;
+
+       return 1;
+}
+
 int metadatatype_arg(struct cmd_context *cmd, struct arg_values *av)
 {
        return get_format_by_name(cmd, av->value) ? 1 : 0;
@@ -279,8 +312,8 @@ static int _size_arg(struct cmd_context *cmd __attribute__((unused)), struct arg
                if (i < 0) {
                        return 0;
                } else if (i == 7) {
-                       /* sectors */
-                       v = v;
+                       /* v is already in sectors */
+                       ;
                } else if (i == 6) {
                        /* bytes */
                        v_tmp = (uint64_t) v;
@@ -373,38 +406,6 @@ int int_arg_with_sign_and_percent(struct cmd_context *cmd __attribute__((unused)
        return 1;
 }
 
-int minor_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av)
-{
-       char *ptr;
-
-       if (!_get_int_arg(av, &ptr) || (*ptr) || (av->sign == SIGN_MINUS))
-               return 0;
-
-       if (av->i_value > 255) {
-               log_error("Minor number outside range 0-255");
-               return 0;
-       }
-
-       return 1;
-}
-
-int major_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av)
-{
-       char *ptr;
-
-       if (!_get_int_arg(av, &ptr) || (*ptr) || (av->sign == SIGN_MINUS))
-               return 0;
-
-       if (av->i_value > 255) {
-               log_error("Major number outside range 0-255");
-               return 0;
-       }
-
-       /* FIXME Also Check against /proc/devices */
-
-       return 1;
-}
-
 int string_arg(struct cmd_context *cmd __attribute__((unused)),
               struct arg_values *av __attribute__((unused)))
 {
@@ -506,6 +507,35 @@ int metadatacopies_arg(struct cmd_context *cmd, struct arg_values *av)
        return int_arg(cmd, av);
 }
 
+int major_minor_valid(const struct cmd_context *cmd, const struct format_type *fmt,
+                     int32_t major, int32_t minor)
+{
+       if (!strncmp(cmd->kernel_vsn, "2.4.", 4) ||
+           (fmt->features & FMT_RESTRICTED_LVIDS)) {
+               if (major < 0 || major > 255) {
+                       log_error("Major number outside range 0-255");
+                       return 0;
+               }
+               if (minor < 0 || minor > 255) {
+                       log_error("Minor number outside range 0-255");
+                       return 0;
+               }
+       } else {
+               /* 12 bits for major number */
+               if (major < 0 || major > 4095) {
+                       log_error("Major number outside range 0-4095");
+                       return 0;
+               }
+               /* 20 bits for minor number */
+               if (minor < 0 || minor > 1048575) {
+                       log_error("Minor number outside range 0-1048575");
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
 static void __alloc(int size)
 {
        if (!(_cmdline.commands = dm_realloc(_cmdline.commands, sizeof(*_cmdline.commands) * size))) {
@@ -646,7 +676,7 @@ static void _add_getopt_arg(int arg, char **ptr, struct option **o)
                if (a->short_arg)
                        (*o)->val = a->short_arg;
                else
-                       (*o)->val = arg;
+                       (*o)->val = arg + 128;
                (*o)++;
        }
 #endif
@@ -667,7 +697,7 @@ static int _find_arg(struct command *com, int opt)
                 * the_args.
                 */
                if ((a->short_arg && (opt == a->short_arg)) ||
-                   (!a->short_arg && (opt == arg)))
+                   (!a->short_arg && (opt == (arg + 128))))
                        return arg;
        }
 
@@ -819,6 +849,9 @@ static int _get_settings(struct cmd_context *cmd)
                cmd->current_settings.verbose = 0;
        }
 
+       if (arg_count(cmd, quiet_ARG) > 1)
+               cmd->current_settings.silent = 1;
+
        if (arg_count(cmd, test_ARG))
                cmd->current_settings.test = arg_count(cmd, test_ARG);
 
@@ -835,7 +868,7 @@ static int _get_settings(struct cmd_context *cmd)
 
        if (arg_count(cmd, partial_ARG)) {
                cmd->partial_activation = 1;
-               log_print("Partial mode. Incomplete logical volumes will be processed.");
+               log_warn("PARTIAL MODE. Incomplete logical volumes will be processed.");
        }
 
        if (arg_count(cmd, ignorelockingfailure_ARG) || arg_count(cmd, sysinit_ARG))
@@ -843,6 +876,9 @@ static int _get_settings(struct cmd_context *cmd)
        else
                init_ignorelockingfailure(0);
 
+       if (!arg_count(cmd, sysinit_ARG))
+               lvmetad_warning();
+
        if (arg_count(cmd, nosuffix_ARG))
                cmd->current_settings.suffix = 0;
 
@@ -865,14 +901,17 @@ static int _get_settings(struct cmd_context *cmd)
        } else
                init_trust_cache(0);
 
-       if (arg_count(cmd, noudevsync_ARG))
+       if (arg_count(cmd, noudevsync_ARG)) {
                cmd->current_settings.udev_sync = 0;
+               cmd->current_settings.udev_fallback = 1;
+       }
 
        /* Handle synonyms */
        if (!_merge_synonym(cmd, resizable_ARG, resizeable_ARG) ||
            !_merge_synonym(cmd, allocation_ARG, allocatable_ARG) ||
            !_merge_synonym(cmd, allocation_ARG, resizeable_ARG) ||
-           !_merge_synonym(cmd, virtualoriginsize_ARG, virtualsize_ARG))
+           !_merge_synonym(cmd, virtualoriginsize_ARG, virtualsize_ARG) ||
+           !_merge_synonym(cmd, available_ARG, activate_ARG))
                return EINVALID_CMD_LINE;
 
        if ((!strncmp(cmd->command->name, "pv", 2) &&
@@ -935,9 +974,11 @@ static void _apply_settings(struct cmd_context *cmd)
 {
        init_debug(cmd->current_settings.debug);
        init_verbose(cmd->current_settings.verbose + VERBOSE_BASE_LEVEL);
+       init_silent(cmd->current_settings.silent);
        init_test(cmd->current_settings.test);
        init_full_scan_done(0);
        init_mirror_in_sync(0);
+       init_dmeventd_monitor(DEFAULT_DMEVENTD_MONITOR);
 
        init_msg_prefix(cmd->default_settings.msg_prefix);
        init_cmd_name(cmd->default_settings.cmd_name);
@@ -953,47 +994,6 @@ static void _apply_settings(struct cmd_context *cmd)
        cmd->handles_missing_pvs = 0;
 }
 
-static int _set_udev_checking(struct cmd_context *cmd)
-{
-#ifdef UDEV_SYNC_SUPPORT
-       struct udev *udev;
-       const char *udev_dev_dir;
-       size_t udev_dev_dir_len;
-       int dirs_diff;
-
-       if (!(udev = udev_new()) ||
-           !(udev_dev_dir = udev_get_dev_path(udev)) ||
-           !*udev_dev_dir) {
-               log_error("Could not get udev dev path.");
-               return 0;
-       }
-       udev_dev_dir_len = strlen(udev_dev_dir);
-
-       /* There's always a slash at the end of dev_dir. But check udev_dev_dir! */
-       if (udev_dev_dir[udev_dev_dir_len - 1] != '/')
-               dirs_diff = strncmp(cmd->dev_dir, udev_dev_dir,
-                                   udev_dev_dir_len);
-       else
-               dirs_diff = strcmp(cmd->dev_dir, udev_dev_dir);
-
-       if (dirs_diff) {
-               log_debug("The path %s used for creating device nodes and "
-                         "symlinks that is set in the configuration differs "
-                         "from the path %s that is used by udev. All warnings "
-                         "about udev not working correctly while processing "
-                         "particular nodes and symlinks will be suppressed. "
-                         "These nodes and symlinks will be managed in each "
-                         "directory separately.",
-                          cmd->dev_dir, udev_dev_dir);
-               dm_udev_set_checking(0);
-               init_udev_checking(0);
-       }
-
-       udev_unref(udev);
-#endif
-       return 1;
-}
-
 static const char *_copy_command_line(struct cmd_context *cmd, int argc, char **argv)
 {
        int i, space;
@@ -1040,6 +1040,8 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
 {
        int ret = 0;
        int locking_type;
+       int monitoring;
+       struct dm_config_tree *old_cft;
 
        init_error_message_produced(0);
 
@@ -1064,8 +1066,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
        set_cmd_name(cmd->command->name);
 
        if (arg_count(cmd, config_ARG))
-               if (override_config_tree_from_string(cmd,
-                   arg_str_value(cmd, config_ARG, ""))) {
+               if (override_config_tree_from_string(cmd, arg_str_value(cmd, config_ARG, ""))) {
                        ret = EINVALID_CMD_LINE;
                        goto_out;
                }
@@ -1073,10 +1074,9 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
        if (arg_count(cmd, config_ARG) || !cmd->config_valid || config_files_changed(cmd)) {
                /* Reinitialise various settings inc. logging, filters */
                if (!refresh_toolcontext(cmd)) {
-                       if (cmd->cft_override) {
-                               destroy_config_tree(cmd->cft_override);
-                               cmd->cft_override = NULL;
-                       }
+                       old_cft = remove_overridden_config_tree(cmd);
+                       if (old_cft)
+                               dm_config_destroy(old_cft);
                        log_error("Updated config file invalid. Aborting.");
                        return ECMD_FAILED;
                }
@@ -1086,17 +1086,21 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
                goto_out;
        _apply_settings(cmd);
 
+       if (!get_activation_monitoring_mode(cmd, &monitoring))
+               goto_out;
+       init_dmeventd_monitor(monitoring);
+
        log_debug("Processing: %s", cmd->cmd_line);
 
 #ifdef O_DIRECT_SUPPORT
        log_debug("O_DIRECT will be used");
 #endif
 
-       if (!_set_udev_checking(cmd))
-               goto_out;
-
-       if ((ret = _process_common_commands(cmd)))
-               goto_out;
+       if ((ret = _process_common_commands(cmd))) {
+               if (ret != ECMD_PROCESSED)
+                       stack;
+               goto out;
+       }
 
        if (cmd->metadata_read_only &&
            !(cmd->command->flags & PERMITTED_READ_ONLY)) {
@@ -1125,9 +1129,8 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
                lvmcache_destroy(cmd, 1);
        }
 
-       if (cmd->cft_override) {
-               destroy_config_tree(cmd->cft_override);
-               cmd->cft_override = NULL;
+       if ((old_cft = remove_overridden_config_tree(cmd))) {
+               dm_config_destroy(old_cft);
                /* Move this? */
                if (!refresh_toolcontext(cmd))
                        stack;
@@ -1187,6 +1190,39 @@ int lvm_split(char *str, int *argc, char **argv, int max)
        return *argc;
 }
 
+/* Make sure we have always valid filedescriptors 0,1,2 */
+static int _check_standard_fds(void)
+{
+       int err = is_valid_fd(STDERR_FILENO);
+
+       if (!is_valid_fd(STDIN_FILENO) &&
+           !(stdin = fopen(_PATH_DEVNULL, "r"))) {
+               if (err)
+                       perror("stdin stream open");
+               else
+                       printf("stdin stream open: %s\n",
+                              strerror(errno));
+               return 0;
+       }
+
+       if (!is_valid_fd(STDOUT_FILENO) &&
+           !(stdout = fopen(_PATH_DEVNULL, "w"))) {
+               if (err)
+                       perror("stdout stream open");
+               /* else no stdout */
+               return 0;
+       }
+
+       if (!is_valid_fd(STDERR_FILENO) &&
+           !(stderr = fopen(_PATH_DEVNULL, "w"))) {
+               printf("stderr stream open: %s\n",
+                      strerror(errno));
+               return 0;
+       }
+
+       return 1;
+}
+
 static const char *_get_cmdline(pid_t pid)
 {
        static char _proc_cmdline[32];
@@ -1195,7 +1231,7 @@ static const char *_get_cmdline(pid_t pid)
 
        snprintf(buf, sizeof(buf), DEFAULT_PROC_DIR "/%u/cmdline", pid);
        /* FIXME Use generic read code. */
-       if ((fd = open(buf, O_RDONLY)) > 0) {
+       if ((fd = open(buf, O_RDONLY)) >= 0) {
                if ((n = read(fd, _proc_cmdline, sizeof(_proc_cmdline) - 1)) < 0) {
                        log_sys_error("read", buf);
                        n = 0;
@@ -1232,7 +1268,7 @@ static void _close_descriptor(int fd, unsigned suppress_warnings,
        const char *filename;
 
        /* Ignore bad file descriptors */
-       if (fcntl(fd, F_GETFD) == -1 && errno == EBADF)
+       if (!is_valid_fd(fd))
                return;
 
        if (!suppress_warnings)
@@ -1254,39 +1290,70 @@ static void _close_descriptor(int fd, unsigned suppress_warnings,
        fprintf(stderr, " Parent PID %" PRIpid_t ": %s\n", ppid, parent_cmdline);
 }
 
-static void _close_stray_fds(const char *command)
+static int _close_stray_fds(const char *command)
 {
+#ifndef VALGRIND_POOL
        struct rlimit rlim;
        int fd;
        unsigned suppress_warnings = 0;
        pid_t ppid = getppid();
        const char *parent_cmdline = _get_cmdline(ppid);
-
-       if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
-               fprintf(stderr, "getrlimit(RLIMIT_NOFILE) failed: %s\n",
-                       strerror(errno));
-               return;
-       }
+       static const char _fd_dir[] = DEFAULT_PROC_DIR "/self/fd";
+       struct dirent *dirent;
+       DIR *d;
 
        if (getenv("LVM_SUPPRESS_FD_WARNINGS"))
                suppress_warnings = 1;
 
-       for (fd = 3; fd < rlim.rlim_cur; fd++)
-               _close_descriptor(fd, suppress_warnings, command, ppid,
-                                 parent_cmdline);
+       if (!(d = opendir(_fd_dir))) {
+               if (errno != ENOENT) {
+                       log_sys_error("opendir", _fd_dir);
+                       return 0; /* broken system */
+               }
+
+               /* Path does not exist, use the old way */
+               if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
+                       log_sys_error("getrlimit", "RLIMIT_NOFILE");
+                       return 1;
+               }
+
+               for (fd = 3; fd < (int)rlim.rlim_cur; fd++)
+                       _close_descriptor(fd, suppress_warnings, command, ppid,
+                                         parent_cmdline);
+               return 1;
+       }
+
+       while ((dirent = readdir(d))) {
+               fd = atoi(dirent->d_name);
+               if (fd > 2 && fd != dirfd(d))
+                       _close_descriptor(fd, suppress_warnings,
+                                         command, ppid, parent_cmdline);
+       }
+
+       if (closedir(d))
+               log_sys_error("closedir", _fd_dir);
+#endif
+
+       return 1;
 }
 
 struct cmd_context *init_lvm(void)
 {
        struct cmd_context *cmd;
 
-       if (!(cmd = create_toolcontext(0, NULL)))
+       if (!udev_init_library_context())
+               stack;
+
+       if (!(cmd = create_toolcontext(0, NULL, 1, 0))) {
+               udev_fin_library_context();
                return_NULL;
+       }
 
        _cmdline.arg_props = &_arg_props[0];
 
        if (stored_errno()) {
                destroy_toolcontext(cmd);
+               udev_fin_library_context();
                return_NULL;
        }
 
@@ -1311,6 +1378,7 @@ void lvm_fin(struct cmd_context *cmd)
 {
        _fin_commands();
        destroy_toolcontext(cmd);
+       udev_fin_library_context();
 }
 
 static int _run_script(struct cmd_context *cmd, int argc, char **argv)
@@ -1421,14 +1489,21 @@ int lvm2_main(int argc, char **argv)
            strcmp(base, "initrd-lvm"))
                alias = 1;
 
-       _close_stray_fds(base);
+       if (!_check_standard_fds())
+               return -1;
+
+       if (!_close_stray_fds(base))
+               return -1;
 
        if (is_static() && strcmp(base, "lvm.static") &&
            path_exists(LVM_SHARED_PATH) &&
            !getenv("LVM_DID_EXEC")) {
-               setenv("LVM_DID_EXEC", base, 1);
-               execvp(LVM_SHARED_PATH, argv);
-               unsetenv("LVM_DID_EXEC");
+               if (setenv("LVM_DID_EXEC", base, 1))
+                       log_sys_error("setenv", "LVM_DID_EXEC");
+               if (execvp(LVM_SHARED_PATH, argv) == -1)
+                       log_sys_error("execvp", "LVM_SHARED_PATH");
+               if (unsetenv("LVM_DID_EXEC"))
+                       log_sys_error("unsetenv", "LVM_DID_EXEC");
        }
 
        /* "version" command is simple enough so it doesn't need any complex init */
index 9127c1561ce4893350be89329b39a379823e3347..df3f0720f5f1b355e8dc9714c3248a30bec0420e 100644 (file)
@@ -72,15 +72,18 @@ static int _check_device(struct cmd_context *cmd, struct device *dev)
        char buffer;
        uint64_t size;
 
-       if (!dev_open(dev)) {
-               return 0;
-       }
+       if (!dev_open_readonly(dev))
+               return_0;
+
        if (!dev_read(dev, UINT64_C(0), (size_t) 1, &buffer)) {
-               dev_close(dev);
+               stack;
+               if (!dev_close(dev))
+                       stack;
                return 0;
        }
        if (!dev_get_size(dev, &size)) {
                log_error("Couldn't get size of \"%s\"", dev_name(dev));
+               size = 0;
        }
        _print(cmd, dev, size, NULL);
        _count(dev, &disks_found, &parts_found);
index 02521495f664398907543350ce1ba93cf68807fa..54094b10deb136017906e1a1c02e5b1b958f3e2e 100644 (file)
@@ -26,7 +26,7 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
         if (lv_is_cow(lv) && lv_is_virtual_origin(origin = origin_from_cow(lv)))
                 lv = origin;
 
-       if (!lv_remove_with_dependencies(cmd, lv, arg_count(cmd, force_ARG), 0)) {
+       if (!lv_remove_with_dependencies(cmd, lv, (force_t) arg_count(cmd, force_ARG), 0)) {
                stack;
                return ECMD_FAILED;
        }
index db47a8bc64f994c093bca0cf797c1eeda0a0896d..3dc21dc794afe3bd65f9dc90c7b3a01b4e9fb604 100644 (file)
@@ -104,7 +104,7 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
        log_verbose("Checking for existing volume group \"%s\"", vg_name);
        vg = vg_read_for_update(cmd, vg_name, NULL, 0);
        if (vg_read_error(vg)) {
-               free_vg(vg);
+               release_vg(vg);
                stack;
                return ECMD_FAILED;
        }
@@ -115,14 +115,29 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
                goto error;
        }
 
+       if (lvl->lv->status & (RAID_IMAGE | RAID_META)) {
+               log_error("Cannot rename a RAID %s directly",
+                         (lvl->lv->status & RAID_IMAGE) ? "image" :
+                         "metadata area");
+               r = ECMD_FAILED;
+               goto error;
+       }
+
+       if (lv_is_raid_with_tracking(lvl->lv)) {
+               log_error("Cannot rename %s while it is tracking a split image",
+                         lvl->lv->name);
+               r = ECMD_FAILED;
+               goto error;
+       }
+
        if (!lv_rename(cmd, lvl->lv, lv_name_new))
                goto error;
 
-       log_print("Renamed \"%s\" to \"%s\" in volume group \"%s\"",
-                 lv_name_old, lv_name_new, vg_name);
+       log_print_unless_silent("Renamed \"%s\" to \"%s\" in volume group \"%s\"",
+                               lv_name_old, lv_name_new, vg_name);
 
        r = ECMD_PROCESSED;
 error:
-       unlock_and_free_vg(cmd, vg, vg_name);
+       unlock_and_release_vg(cmd, vg, vg_name);
        return r;
 }
index c970f3f5381c74d8b6f693e7a52efe926dccd120..4c9580d129fbee546076e2828c3ed1db0d9de115 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -50,12 +50,12 @@ static int _validate_stripesize(struct cmd_context *cmd,
                                const struct volume_group *vg,
                                struct lvresize_params *lp)
 {
-       if (arg_sign_value(cmd, stripesize_ARG, 0) == SIGN_MINUS) {
+       if (arg_sign_value(cmd, stripesize_ARG, SIGN_NONE) == SIGN_MINUS) {
                log_error("Stripesize may not be negative.");
                return 0;
        }
 
-       if (arg_uint_value(cmd, stripesize_ARG, 0) > STRIPE_SIZE_LIMIT * 2) {
+       if (arg_uint64_value(cmd, stripesize_ARG, 0) > STRIPE_SIZE_LIMIT * 2) {
                log_error("Stripe size cannot be larger than %s",
                          display_size(cmd, (uint64_t) STRIPE_SIZE_LIMIT));
                return 0;
@@ -63,7 +63,7 @@ static int _validate_stripesize(struct cmd_context *cmd,
 
        if (!(vg->fid->fmt->features & FMT_SEGMENTS))
                log_warn("Varied stripesize not supported. Ignoring.");
-       else if (arg_uint_value(cmd, stripesize_ARG, 0) > vg->extent_size * 2) {
+       else if (arg_uint_value(cmd, stripesize_ARG, 0) > (uint64_t) vg->extent_size * 2) {
                log_error("Reducing stripe size %s to maximum, "
                          "physical extent size %s",
                          display_size(cmd,
@@ -86,9 +86,7 @@ static int _request_confirmation(struct cmd_context *cmd,
                                 const struct logical_volume *lv,
                                 const struct lvresize_params *lp)
 {
-       struct lvinfo info;
-
-       memset(&info, 0, sizeof(info));
+       struct lvinfo info = { 0 };
 
        if (!lv_info(cmd, lv, 0, &info, 1, 0) && driver_version(NULL, 0)) {
                log_error("lv_info failed: aborting");
@@ -159,6 +157,9 @@ static int _fsadm_cmd(struct cmd_context *cmd,
 
        argv[i++] = (fcmd == FSADM_CMD_RESIZE) ? "resize" : "check";
 
+       if (status)
+               *status = -1;
+
        if (dm_snprintf(lv_path, PATH_MAX, "%s%s/%s", cmd->dev_dir, lp->vg_name,
                        lp->lv_name) < 0) {
                log_error("Couldn't create LV path for %s", lp->lv_name);
@@ -179,7 +180,7 @@ static int _fsadm_cmd(struct cmd_context *cmd,
 
        argv[i] = NULL;
 
-       return exec_cmd(cmd, argv, status);
+       return exec_cmd(cmd, argv, status, 1);
 }
 
 static int _lvresize_params(struct cmd_context *cmd, int argc, char **argv,
@@ -285,37 +286,93 @@ static int _adjust_policy_params(struct cmd_context *cmd,
        percent_t percent;
        int policy_threshold, policy_amount;
 
-       policy_threshold =
-               find_config_tree_int(cmd, "activation/snapshot_autoextend_threshold",
-                                    DEFAULT_SNAPSHOT_AUTOEXTEND_THRESHOLD) * PERCENT_1;
-       policy_amount =
-               find_config_tree_int(cmd, "activation/snapshot_autoextend_percent",
-                                    DEFAULT_SNAPSHOT_AUTOEXTEND_PERCENT);
+       if (lv_is_thin_pool(lv)) {
+               policy_threshold =
+                       find_config_tree_int(cmd, "activation/thin_pool_autoextend_threshold",
+                                            DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD) * PERCENT_1;
+               policy_amount =
+                       find_config_tree_int(cmd, "activation/thin_pool_autoextend_percent",
+                                            DEFAULT_THIN_POOL_AUTOEXTEND_PERCENT);
+               if (!policy_amount && policy_threshold < PERCENT_100)
+                        return 0;
+       } else {
+               policy_threshold =
+                       find_config_tree_int(cmd, "activation/snapshot_autoextend_threshold",
+                                            DEFAULT_SNAPSHOT_AUTOEXTEND_THRESHOLD) * PERCENT_1;
+               policy_amount =
+                       find_config_tree_int(cmd, "activation/snapshot_autoextend_percent",
+                                            DEFAULT_SNAPSHOT_AUTOEXTEND_PERCENT);
+       }
 
        if (policy_threshold >= PERCENT_100)
                return 1; /* nothing to do */
 
-       if (!lv_snapshot_percent(lv, &percent))
-               return_0;
+       if (lv_is_thin_pool(lv)) {
+               if (!lv_thin_pool_percent(lv, 1, &percent))
+                       return_0;
+               if (percent > policy_threshold) {
+                       /* FIXME: metadata resize support missing */
+                       log_error("Resize for %s/%s is not yet supported.",
+                                 lp->vg_name, lp->lv_name);
+                       return ECMD_FAILED;
+               }
 
-       if (!(PERCENT_0 < percent && percent < PERCENT_100) || percent <= policy_threshold)
-               return 1; /* nothing to do */
+               if (!lv_thin_pool_percent(lv, 0, &percent))
+                       return_0;
+               if (!(PERCENT_0 < percent && percent <= PERCENT_100) ||
+                   percent <= policy_threshold)
+                       return 1; /* nothing to do */
+       } else {
+               if (!lv_snapshot_percent(lv, &percent))
+                       return_0;
+               if (!(PERCENT_0 < percent && percent < PERCENT_100) || percent <= policy_threshold)
+                       return 1; /* nothing to do */
+       }
 
        lp->extents = policy_amount;
+
        return 1;
 }
 
+static uint32_t lvseg_get_stripes(struct lv_segment *seg, uint32_t *stripesize)
+{
+       uint32_t s;
+       struct lv_segment *seg_mirr;
+
+       /* If segment mirrored, check if images are striped */
+       if (seg_is_mirrored(seg))
+               for (s = 0; s < seg->area_count; s++) {
+                       if (seg_type(seg, s) != AREA_LV)
+                               continue;
+                       seg_mirr = first_seg(seg_lv(seg, s));
+
+                       if (seg_is_striped(seg_mirr)) {
+                               seg = seg_mirr;
+                               break;
+                       }
+               }
+
+
+       if (seg_is_striped(seg)) {
+               *stripesize = seg->stripe_size;
+               return seg->area_count;
+       }
+
+       *stripesize = 0;
+       return 0;
+}
+
 static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
                     struct lvresize_params *lp)
 {
        struct logical_volume *lv;
        struct lvinfo info;
-       uint32_t stripesize_extents = 0;
-       uint32_t seg_stripes = 0, seg_stripesize = 0, seg_size = 0;
+       uint32_t stripesize_extents;
+       uint32_t seg_stripes = 0, seg_stripesize = 0, seg_size;
        uint32_t seg_mirrors = 0;
-       uint32_t extents_used = 0;
+       uint32_t extents_used;
        uint32_t size_rest;
-       uint32_t pv_extent_count = 0;
+       uint32_t pv_extent_count;
        alloc_policy_t alloc;
        struct logical_volume *lock_lv;
        struct lv_list *lvl;
@@ -333,6 +390,19 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
                return ECMD_FAILED;
        }
 
+       if (lvl->lv->status & (RAID_IMAGE | RAID_META)) {
+               log_error("Cannot resize a RAID %s directly",
+                         (lvl->lv->status & RAID_IMAGE) ? "image" :
+                         "metadata area");
+               return ECMD_FAILED;
+       }
+
+       if (lv_is_raid_with_tracking(lvl->lv)) {
+               log_error("Cannot resize %s while it is tracking a split image",
+                         lvl->lv->name);
+               return ECMD_FAILED;
+       }
+
        if (arg_count(cmd, stripes_ARG)) {
                if (vg->fid->fmt->features & FMT_SEGMENTS)
                        lp->stripes = arg_uint_value(cmd, stripes_ARG, 1);
@@ -345,7 +415,7 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
                        lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 1) + 1;
                else
                        log_warn("Mirrors not supported. Ignoring.");
-               if (arg_sign_value(cmd, mirrors_ARG, 0) == SIGN_MINUS) {
+               if (arg_sign_value(cmd, mirrors_ARG, SIGN_NONE) == SIGN_MINUS) {
                        log_error("Mirrors argument may not be negative");
                        return EINVALID_CMD_LINE;
                }
@@ -358,11 +428,13 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
        lv = lvl->lv;
 
        if (use_policy) {
-               if (!lv_is_cow(lv)) {
-                       log_error("Can't use policy-based resize for non-snapshot volumes.");
+               if (!lv_is_cow(lv) &&
+                   !lv_is_thin_pool(lv)) {
+                       log_error("Policy-based resize is supported only for snapshot and thin pool volumes.");
                        return ECMD_FAILED;
                }
-               _adjust_policy_params(cmd, lv, lp);
+               if (!_adjust_policy_params(cmd, lv, lp))
+                       return ECMD_FAILED;
        }
 
        if (!lv_is_visible(lv)) {
@@ -380,8 +452,14 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
                return ECMD_FAILED;
        }
 
-       alloc = arg_uint_value(cmd, alloc_ARG, lv->alloc);
+       alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, lv->alloc);
 
+       /*
+        * First adjust to an exact multiple of extent size.
+        * When extending by a relative amount we round that amount up.
+        * When reducing by a relative amount we remove at most that amount.
+        * When changing to an absolute size, we round that size up.
+        */
        if (lp->size) {
                if (lp->size % vg->extent_size) {
                        if (lp->sign == SIGN_MINUS)
@@ -390,8 +468,8 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
                                lp->size += vg->extent_size -
                                    (lp->size % vg->extent_size);
 
-                       log_print("Rounding up size to full physical extent %s",
-                                 display_size(cmd, (uint64_t) lp->size));
+                       log_print_unless_silent("Rounding size to boundary between physical extents: %s",
+                                               display_size(cmd, lp->size));
                }
 
                lp->extents = lp->size / vg->extent_size;
@@ -405,34 +483,46 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
 
        switch(lp->percent) {
                case PERCENT_VG:
-                       lp->extents = lp->extents * vg->extent_count / 100;
+                       lp->extents = percent_of_extents(lp->extents, vg->extent_count,
+                                                        (lp->sign != SIGN_MINUS));
                        break;
                case PERCENT_FREE:
-                       lp->extents = lp->extents * vg->free_count / 100;
+                       lp->extents = percent_of_extents(lp->extents, vg->free_count,
+                                                        (lp->sign != SIGN_MINUS));
                        break;
                case PERCENT_LV:
-                       lp->extents = lp->extents * lv->le_count / 100;
+                       lp->extents = percent_of_extents(lp->extents, lv->le_count,
+                                                        (lp->sign != SIGN_MINUS));
                        break;
                case PERCENT_PVS:
                        if (lp->argc) {
                                pv_extent_count = pv_list_extents_free(pvh);
-                               lp->extents = lp->extents * pv_extent_count / 100;
+                               lp->extents = percent_of_extents(lp->extents, pv_extent_count,
+                                                                (lp->sign != SIGN_MINUS));
                        } else
-                               lp->extents = lp->extents * vg->extent_count / 100;
+                               lp->extents = percent_of_extents(lp->extents, vg->extent_count,
+                                                                (lp->sign != SIGN_MINUS));
                        break;
                case PERCENT_ORIGIN:
                        if (!lv_is_cow(lv)) {
                                log_error("Specified LV does not have an origin LV.");
                                return EINVALID_CMD_LINE;
                        }
-                       lp->extents = lp->extents * origin_from_cow(lv)->le_count / 100;
+                       lp->extents = percent_of_extents(lp->extents, origin_from_cow(lv)->le_count,
+                                                        (lp->sign != SIGN_MINUS));
                        break;
                case PERCENT_NONE:
                        break;
        }
 
-       if (lp->sign == SIGN_PLUS)
+       if (lp->sign == SIGN_PLUS) {
+               if (lp->extents >= (MAX_EXTENT_COUNT - lv->le_count)) {
+                       log_error("Unable to extend %s by %u extents, exceeds limit (%u).",
+                                 lp->lv_name, lv->le_count, MAX_EXTENT_COUNT);
+                       return EINVALID_CMD_LINE;
+               }
                lp->extents += lv->le_count;
+       }
 
        if (lp->sign == SIGN_MINUS) {
                if (lp->extents >= lv->le_count) {
@@ -476,6 +566,13 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
 
        /* If extending, find mirrors of last segment */
        if ((lp->extents > lv->le_count)) {
+               /*
+                * Has the user specified that they would like the additional
+                * extents of a mirror not to have an initial sync?
+                */
+               if (seg_is_mirrored(first_seg(lv)) && arg_count(cmd, nosync_ARG))
+                       lv->status |= LV_NOTSYNCED;
+
                dm_list_iterate_back_items(mirr_seg, &lv->segments) {
                        if (seg_is_mirrored(mirr_seg))
                                seg_mirrors = lv_mirror_count(mirr_seg->lv);
@@ -483,9 +580,10 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
                                seg_mirrors = 0;
                        break;
                }
+
                if (!arg_count(cmd, mirrors_ARG) && seg_mirrors) {
-                       log_print("Extending %" PRIu32 " mirror images.",
-                                 seg_mirrors);
+                       log_print_unless_silent("Extending %" PRIu32 " mirror images.",
+                                               seg_mirrors);
                        lp->mirrors = seg_mirrors;
                }
                if ((arg_count(cmd, mirrors_ARG) || seg_mirrors) &&
@@ -493,18 +591,30 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
                        log_error("Cannot vary number of mirrors in LV yet.");
                        return EINVALID_CMD_LINE;
                }
+
+               if (seg_mirrors && !strcmp(mirr_seg->segtype->name, "raid10")) {
+                       lp->stripes = mirr_seg->area_count / seg_mirrors;
+                       lp->stripe_size = mirr_seg->stripe_size;
+               }
        }
 
        /* If extending, find stripes, stripesize & size of last segment */
        if ((lp->extents > lv->le_count) &&
-           !(lp->stripes == 1 || (lp->stripes > 1 && lp->stripe_size))) {
+           !(lp->stripes == 1 || (lp->stripes > 1 && lp->stripe_size)) &&
+           strcmp(mirr_seg->segtype->name, "raid10")) {
                /* FIXME Don't assume mirror seg will always be AREA_LV */
-               dm_list_iterate_items(seg, seg_mirrors ? &seg_lv(mirr_seg, 0)->segments : &lv->segments) {
-                       if (!seg_is_striped(seg))
+               /* FIXME We will need to support resize for metadata LV as well,
+                *       and data LV could be any type (i.e. mirror)) */
+               dm_list_iterate_items(seg, seg_mirrors ? &seg_lv(mirr_seg, 0)->segments :
+                                     lv_is_thin_pool(lv) ? &seg_lv(first_seg(lv), 0)->segments : &lv->segments) {
+                       /* Allow through "striped" and RAID 4/5/6/10 */
+                       if (!seg_is_striped(seg) &&
+                           (!seg_is_raid(seg) || seg_is_mirrored(seg)) &&
+                           strcmp(seg->segtype->name, "raid10"))
                                continue;
 
                        sz = seg->stripe_size;
-                       str = seg->area_count;
+                       str = seg->area_count - lp->segtype->parity_devs;
 
                        if ((seg_stripesize && seg_stripesize != sz &&
                             sz && !lp->stripe_size) ||
@@ -520,19 +630,24 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
 
                if (!lp->stripes)
                        lp->stripes = seg_stripes;
+               else if (seg_is_raid(first_seg(lv)) &&
+                        (lp->stripes != seg_stripes)) {
+                       log_error("Unable to extend \"%s\" segment type with different number of stripes.", first_seg(lv)->segtype->ops->name(first_seg(lv)));
+                       return ECMD_FAILED;
+               }
 
                if (!lp->stripe_size && lp->stripes > 1) {
                        if (seg_stripesize) {
-                               log_print("Using stripesize of last segment %s",
-                                         display_size(cmd, (uint64_t) seg_stripesize));
+                               log_print_unless_silent("Using stripesize of last segment %s",
+                                                       display_size(cmd, (uint64_t) seg_stripesize));
                                lp->stripe_size = seg_stripesize;
                        } else {
                                lp->stripe_size =
                                        find_config_tree_int(cmd,
                                                        "metadata/stripesize",
                                                        DEFAULT_STRIPESIZE) * 2;
-                               log_print("Using default stripesize %s",
-                                         display_size(cmd, (uint64_t) lp->stripe_size));
+                               log_print_unless_silent("Using default stripesize %s",
+                                                       display_size(cmd, (uint64_t) lp->stripe_size));
                        }
                }
        }
@@ -548,10 +663,8 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
                dm_list_iterate_items(seg, &lv->segments) {
                        seg_extents = seg->len;
 
-                       if (seg_is_striped(seg)) {
-                               seg_stripesize = seg->stripe_size;
-                               seg_stripes = seg->area_count;
-                       }
+                       /* Check for underlying stripe sizes */
+                       seg_stripes = lvseg_get_stripes(seg, &seg_stripesize);
 
                        if (seg_is_mirrored(seg))
                                seg_mirrors = lv_mirror_count(seg->lv);
@@ -575,22 +688,35 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
                return EINVALID_CMD_LINE;
        }
 
-       if ((lp->stripes > 1)) {
-               if (!(stripesize_extents = lp->stripe_size / vg->extent_size))
-                       stripesize_extents = 1;
-
-               if ((size_rest = seg_size % (lp->stripes * stripesize_extents))) {
-                       log_print("Rounding size (%d extents) down to stripe "
-                                 "boundary size for segment (%d extents)",
-                                 lp->extents, lp->extents - size_rest);
-                       lp->extents = lp->extents - size_rest;
-               }
-
+       if (lp->stripes > 1) {
                if (lp->stripe_size < STRIPE_SIZE_MIN) {
                        log_error("Invalid stripe size %s",
                                  display_size(cmd, (uint64_t) lp->stripe_size));
                        return EINVALID_CMD_LINE;
                }
+
+               if (!(stripesize_extents = lp->stripe_size / vg->extent_size))
+                       stripesize_extents = 1;
+
+               size_rest = seg_size % (lp->stripes * stripesize_extents);
+               /* Round toward the original size. */
+               if (size_rest &&
+                   ((lp->extents < lv->le_count) ||
+                    !lp->percent ||
+                    (vg->free_count >= (lp->extents - lv->le_count - size_rest +
+                                        (lp->stripes * stripesize_extents))))) {
+                       log_print_unless_silent("Rounding size (%d extents) up to stripe "
+                                               "boundary size for segment (%d extents)",
+                                               lp->extents, lp->extents - size_rest +
+                                               (lp->stripes * stripesize_extents));
+                       lp->extents = lp->extents - size_rest +
+                                     (lp->stripes * stripesize_extents);
+               } else if (size_rest) {
+                       log_print_unless_silent("Rounding size (%d extents) down to stripe "
+                                               "boundary size for segment (%d extents)",
+                                               lp->extents, lp->extents - size_rest);
+                       lp->extents = lp->extents - size_rest;
+               }
        }
 
        if (lp->extents < lv->le_count) {
@@ -609,6 +735,15 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
                        return EINVALID_CMD_LINE;
                }
                lp->resize = LV_EXTEND;
+       } else if (lp->extents == lv->le_count) {
+               if (use_policy)
+                       return ECMD_PROCESSED; /* Nothing to do. */
+               if (!lp->resizefs) {
+                       log_error("New size (%d extents) matches existing size "
+                                 "(%d extents)", lp->extents, lv->le_count);
+                       return EINVALID_CMD_LINE;
+               }
+               lp->resize = LV_EXTEND;
        }
 
        if (lv_is_origin(lv)) {
@@ -618,8 +753,6 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
                        return ECMD_FAILED;
                }
 
-               memset(&info, 0, sizeof(info));
-
                if (lv_info(cmd, lv, 0, &info, 0, 0) && info.exists) {
                        log_error("Snapshot origin volumes can be resized "
                                  "only while inactive: try lvchange -an");
@@ -627,6 +760,18 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
                }
        }
 
+       if (lv_is_thin_pool(lv)) {
+               if (lp->resize == LV_REDUCE) {
+                       log_error("Thin pool volumes cannot be reduced in size yet.");
+                       return ECMD_FAILED;
+               }
+
+               if (lp->resizefs) {
+                       log_warn("Thin pool volumes do not have filesystem.");
+                       lp->resizefs = 0;
+               }
+       }
+
        if ((lp->resize == LV_REDUCE) && lp->argc)
                log_warn("Ignoring PVs on command line when reducing");
 
@@ -641,15 +786,15 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
                if (!lp->nofsck &&
                    !_fsadm_cmd(cmd, vg, lp, FSADM_CMD_CHECK, &status)) {
                        if (status != FSADM_CHECK_FAILS_FOR_MOUNTED) {
-                               stack;
+                               log_error("Filesystem check failed.");
                                return ECMD_FAILED;
                        }
-                        /* some filesystems supports online resize */
+                       /* some filesystems supports online resize */
                }
 
                if ((lp->resize == LV_REDUCE) &&
                    !_fsadm_cmd(cmd, vg, lp, FSADM_CMD_RESIZE, NULL)) {
-                       stack;
+                       log_error("Filesystem resize failed.");
                        return ECMD_FAILED;
                }
        }
@@ -659,10 +804,10 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
                return ECMD_FAILED;
        }
 
-       log_print("%sing logical volume %s to %s",
-                 (lp->resize == LV_REDUCE) ? "Reduc" : "Extend",
-                 lp->lv_name,
-                 display_size(cmd, (uint64_t) lp->extents * vg->extent_size));
+       log_print_unless_silent("%sing logical volume %s to %s",
+                               (lp->resize == LV_REDUCE) ? "Reduc" : "Extend",
+                               lp->lv_name,
+                               display_size(cmd, (uint64_t) lp->extents * vg->extent_size));
 
        if (lp->resize == LV_REDUCE) {
                if (!lv_reduce(lv, lv->le_count - lp->extents)) {
@@ -670,10 +815,11 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
                        return ECMD_FAILED;
                }
        } else if ((lp->extents > lv->le_count) && /* Ensure we extend */
-                  !lv_extend(lv, lp->segtype, lp->stripes,
-                             lp->stripe_size, lp->mirrors,
-                             lp->extents - lv->le_count,
-                             NULL, 0u, 0u, pvh, alloc)) {
+                  !lv_extend(lv, lp->segtype,
+                             lp->stripes, lp->stripe_size,
+                             lp->mirrors, first_seg(lv)->region_size,
+                             lp->extents - lv->le_count, NULL,
+                             pvh, alloc)) {
                stack;
                return ECMD_FAILED;
        }
@@ -713,7 +859,21 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
 
        backup(vg);
 
-       log_print("Logical volume %s successfully resized", lp->lv_name);
+       /*
+        * Update lvm pool metadata (drop messages) if the pool has been
+        * resumed and do a pool active/deactivate in other case.
+        *
+        * Note: Active thin pool can be waiting for resize.
+        *
+        * FIXME: Activate only when thin volume is active
+        */
+       if (lv_is_thin_pool(lv) &&
+           !update_pool_lv(lv, !lv_is_active(lv))) {
+               stack;
+               return ECMD_FAILED;
+       }
+
+       log_print_unless_silent("Logical volume %s successfully resized", lp->lv_name);
 
        if (lp->resizefs && (lp->resize == LV_EXTEND) &&
            !_fsadm_cmd(cmd, vg, lp, FSADM_CMD_RESIZE, NULL)) {
@@ -726,19 +886,17 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
 
 int lvresize(struct cmd_context *cmd, int argc, char **argv)
 {
-       struct lvresize_params lp;
+       struct lvresize_params lp = { 0 };
        struct volume_group *vg;
        int r;
 
-       memset(&lp, 0, sizeof(lp));
-
        if (!_lvresize_params(cmd, argc, argv, &lp))
                return EINVALID_CMD_LINE;
 
        log_verbose("Finding volume group %s", lp.vg_name);
        vg = vg_read_for_update(cmd, lp.vg_name, NULL, 0);
        if (vg_read_error(vg)) {
-               free_vg(vg);
+               release_vg(vg);
                stack;
                return ECMD_FAILED;
        }
@@ -746,7 +904,7 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
        if (!(r = _lvresize(cmd, vg, &lp)))
                stack;
 
-       unlock_and_free_vg(cmd, vg, lp.vg_name);
+       unlock_and_release_vg(cmd, vg, lp.vg_name);
 
        return r;
 }
index 638d2f57ace6cb8f303d48e2721cc7fcffd6d5db..636ac453847d8800eac79083692b5e65e97acefb 100644 (file)
@@ -19,8 +19,6 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv,
                         void *handle __attribute__((unused)))
 {
        struct lvinfo info;
-       int lv_total = 0;
-       uint64_t lv_capacity_total = 0;
        int inkernel, snap_active = 1;
        struct lv_segment *snap_seg = NULL;
        percent_t snap_percent;     /* fused, fsize; */
@@ -30,7 +28,7 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv,
        if (!arg_count(cmd, all_ARG) && !lv_is_visible(lv))
                return ECMD_PROCESSED;
 
-       inkernel = lv_info(cmd, lv, 0, &info, 1, 0) && info.exists;
+       inkernel = lv_info(cmd, lv, 0, &info, 0, 0) && info.exists;
        if (lv_is_origin(lv)) {
                dm_list_iterate_items_gen(snap_seg, &lv->snapshot_segs,
                                       origin_list) {
@@ -61,14 +59,10 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv,
        else
                snapshot_str = "        ";
 
-       log_print("%s%s '%s%s/%s' [%s] %s", active_str, snapshot_str,
-                 cmd->dev_dir, lv->vg->name, lv->name,
-                 display_size(cmd, lv->size),
-                 get_alloc_string(lv->alloc));
-
-       lv_total++;
-
-       lv_capacity_total += lv->size;
+       log_print_unless_silent("%s%s '%s%s/%s' [%s] %s", active_str, snapshot_str,
+                               cmd->dev_dir, lv->vg->name, lv->name,
+                               display_size(cmd, lv->size),
+                               get_alloc_string(lv->alloc));
 
        return ECMD_PROCESSED;
 }
index 50579baba7679ca7f9ba759a0fc936f51fcdae40..a9138a15b95f663017b4e7efab794f0e0b2575d7 100644 (file)
@@ -32,6 +32,8 @@ static void _sigchld_handler(int sig __attribute__((unused)))
  */
 static int _become_daemon(struct cmd_context *cmd)
 {
+       static const char devnull[] = "/dev/null";
+       int null_fd;
        pid_t pid;
        struct sigaction act = {
                {_sigchld_handler},
@@ -42,6 +44,8 @@ static int _become_daemon(struct cmd_context *cmd)
 
        sigaction(SIGCHLD, &act, NULL);
 
+       sync_local_dev_names(cmd); /* Flush ops and reset dm cookie */
+
        if ((pid = fork()) == -1) {
                log_error("fork failed: %s", strerror(errno));
                return -1;
@@ -55,16 +59,33 @@ static int _become_daemon(struct cmd_context *cmd)
        if (setsid() == -1)
                log_error("Background process failed to setsid: %s",
                          strerror(errno));
-       init_verbose(VERBOSE_BASE_LEVEL);
 
-       close(STDIN_FILENO);
-       close(STDOUT_FILENO);
-       close(STDERR_FILENO);
+       /* For poll debugging it's best to disable for compilation */
+#if 1
+       if ((null_fd = open(devnull, O_RDWR)) == -1) {
+               log_sys_error("open", devnull);
+               _exit(ECMD_FAILED);
+       }
+
+       if ((dup2(null_fd, STDIN_FILENO) < 0)  || /* reopen stdin */
+           (dup2(null_fd, STDOUT_FILENO) < 0) || /* reopen stdout */
+           (dup2(null_fd, STDERR_FILENO) < 0)) { /* reopen stderr */
+               log_sys_error("dup2", "redirect");
+               (void) close(null_fd);
+               _exit(ECMD_FAILED);
+       }
+
+       if (null_fd > STDERR_FILENO)
+               (void) close(null_fd);
 
+       init_verbose(VERBOSE_BASE_LEVEL);
+#endif
        strncpy(*cmd->argv, "(lvm2)", strlen(*cmd->argv));
 
        reset_locking();
-       lvmcache_init();
+       if (!lvmcache_init())
+               /* FIXME Clean up properly here */
+               _exit(ECMD_FAILED);
        dev_close_all();
 
        return 1;
@@ -87,8 +108,8 @@ progress_t poll_mirror_progress(struct cmd_context *cmd,
 
        overall_percent = copy_percent(lv);
        if (parms->progress_display)
-               log_print("%s: %s: %.1f%%", name, parms->progress_title,
-                         percent_to_float(overall_percent));
+               log_print_unless_silent("%s: %s: %.1f%%", name, parms->progress_title,
+                                       percent_to_float(overall_percent));
        else
                log_verbose("%s: %s: %.1f%%", name, parms->progress_title,
                            percent_to_float(overall_percent));
@@ -144,7 +165,7 @@ static int _check_lv_status(struct cmd_context *cmd,
        /* Finished? Or progress to next segment? */
        if (progress == PROGRESS_FINISHED_ALL) {
                if (!parms->poll_fns->finish_copy(cmd, vg, lv, lvs_changed))
-                       return 0;
+                       return_0;
        } else {
                if (parms->poll_fns->update_metadata &&
                    !parms->poll_fns->update_metadata(cmd, vg, lv, lvs_changed, 0)) {
@@ -183,26 +204,34 @@ static int _wait_for_single_lv(struct cmd_context *cmd, const char *name, const
                /* Locks the (possibly renamed) VG again */
                vg = parms->poll_fns->get_copy_vg(cmd, name, uuid);
                if (vg_read_error(vg)) {
-                       free_vg(vg);
+                       release_vg(vg);
                        log_error("ABORTING: Can't reread VG for %s", name);
                        /* What more could we do here? */
                        return 0;
                }
 
-               if (!(lv = parms->poll_fns->get_copy_lv(cmd, vg, name, uuid,
-                                                       parms->lv_type))) {
+               lv = parms->poll_fns->get_copy_lv(cmd, vg, name, uuid, parms->lv_type);
+
+               if (!lv && parms->lv_type == PVMOVE) {
+                       log_print_unless_silent("%s: no pvmove in progress - already finished or aborted.",
+                                               name);
+                       unlock_and_release_vg(cmd, vg, vg->name);
+                       return 1;
+               }
+
+               if (!lv) {
                        log_error("ABORTING: Can't find LV in %s for %s",
                                  vg->name, name);
-                       unlock_and_free_vg(cmd, vg, vg->name);
+                       unlock_and_release_vg(cmd, vg, vg->name);
                        return 0;
                }
 
                if (!_check_lv_status(cmd, vg, lv, name, parms, &finished)) {
-                       unlock_and_free_vg(cmd, vg, vg->name);
-                       return 0;
+                       unlock_and_release_vg(cmd, vg, vg->name);
+                       return_0;
                }
 
-               unlock_and_free_vg(cmd, vg, vg->name);
+               unlock_and_release_vg(cmd, vg, vg->name);
 
                /*
                 * FIXME Sleeping after testing, while preferred, also works around
@@ -232,6 +261,11 @@ static int _poll_vg(struct cmd_context *cmd, const char *vgname,
        const char *name;
        int finished;
 
+       if (!parms) {
+               log_error(INTERNAL_ERROR "Handle is undefined.");
+               return ECMD_FAILED;
+       }
+
        dm_list_iterate_items(lvl, &vg->lvs) {
                lv = lvl->lv;
                if (!(lv->status & parms->lv_type))
@@ -271,7 +305,7 @@ static void _poll_for_all_vgs(struct cmd_context *cmd,
  */
 int poll_daemon(struct cmd_context *cmd, const char *name, const char *uuid,
                unsigned background,
-               uint32_t lv_type, struct poll_functions *poll_fns,
+               uint64_t lv_type, struct poll_functions *poll_fns,
                const char *progress_title)
 {
        struct daemon_parms parms;
@@ -281,7 +315,7 @@ int poll_daemon(struct cmd_context *cmd, const char *name, const char *uuid,
 
        parms.aborting = arg_is_set(cmd, abort_ARG);
        parms.background = background;
-       interval_sign = arg_sign_value(cmd, interval_ARG, 0);
+       interval_sign = arg_sign_value(cmd, interval_ARG, SIGN_NONE);
        if (interval_sign == SIGN_MINUS)
                log_error("Argument to --interval cannot be negative");
        parms.interval = arg_uint_value(cmd, interval_ARG,
index 8ebbb2568dd2250d643e83fc2180105a5965bf2a..78ea783afcb093c205c2d7bf0ff9a001da740ca4 100644 (file)
@@ -36,7 +36,7 @@ struct poll_functions {
                                               struct volume_group *vg,
                                               const char *name,
                                               const char *uuid,
-                                              uint32_t lv_type);
+                                              uint64_t lv_type);
        progress_t (*poll_progress)(struct cmd_context *cmd,
                                    struct logical_volume *lv,
                                    const char *name,
@@ -59,13 +59,13 @@ struct daemon_parms {
        unsigned outstanding_count;
        unsigned progress_display;
        const char *progress_title;
-       uint32_t lv_type;
+       uint64_t lv_type;
        struct poll_functions *poll_fns;
 };
 
 int poll_daemon(struct cmd_context *cmd, const char *name, const char *uuid,
                unsigned background,
-               uint32_t lv_type, struct poll_functions *poll_fns,
+               uint64_t lv_type, struct poll_functions *poll_fns,
                const char *progress_title);
 
 progress_t poll_mirror_progress(struct cmd_context *cmd,
index 28e71b845b484887221a7d35c84e899ed3214acb..70f1e62942afc57b59f31a4b18da79afaafdf282 100644 (file)
@@ -15,8 +15,6 @@
 
 #include "tools.h"
 
-/* FIXME Locking.  PVs in VG. */
-
 static int _pvchange_single(struct cmd_context *cmd, struct volume_group *vg,
                            struct physical_volume *pv,
                            void *handle __attribute__((unused)))
@@ -27,21 +25,14 @@ static int _pvchange_single(struct cmd_context *cmd, struct volume_group *vg,
        uint64_t orig_pe_start;
 
        const char *pv_name = pv_dev_name(pv);
-       const char *tag = NULL;
        const char *orig_vg_name;
        char uuid[64] __attribute__((aligned(8)));
 
        int allocatable = 0;
-       int tagarg = 0;
-       int r = 0;
+       int tagargs = 0;
        int mda_ignore = 0;
 
-       struct arg_value_group_list *current_group;
-
-       if (arg_count(cmd, addtag_ARG))
-               tagarg = addtag_ARG;
-       else if (arg_count(cmd, deltag_ARG))
-               tagarg = deltag_ARG;
+       tagargs = arg_count(cmd, addtag_ARG) + arg_count(cmd, deltag_ARG);
 
        if (arg_count(cmd, allocatable_ARG))
                allocatable = !strcmp(arg_str_value(cmd, allocatable_ARG, "n"),
@@ -52,20 +43,20 @@ static int _pvchange_single(struct cmd_context *cmd, struct volume_group *vg,
 
        /* If in a VG, must change using volume group. */
        if (!is_orphan(pv)) {
-               if (tagarg && !(vg->fid->fmt->features & FMT_TAGS)) {
+               if (tagargs && !(vg->fid->fmt->features & FMT_TAGS)) {
                        log_error("Volume group containing %s does not "
                                  "support tags", pv_name);
-                       goto out;
+                       return 0;
                }
                if (arg_count(cmd, uuid_ARG) && lvs_in_vg_activated(vg)) {
                        log_error("Volume group containing %s has active "
                                  "logical volumes", pv_name);
-                       goto out;
+                       return 0;
                }
                if (!archive(vg))
-                       goto out;
+                       return 0;
        } else {
-               if (tagarg) {
+               if (tagargs) {
                        log_error("Can't change tag on Physical Volume %s not "
                                  "in volume group", pv_name);
                        return 0;
@@ -77,22 +68,20 @@ static int _pvchange_single(struct cmd_context *cmd, struct volume_group *vg,
                    !(pv->fmt->features & FMT_ORPHAN_ALLOCATABLE)) {
                        log_error("Allocatability not supported by orphan "
                                  "%s format PV %s", pv->fmt->name, pv_name);
-                       goto out;
+                       return 0;
                }
 
                /* change allocatability for a PV */
                if (allocatable && (pv_status(pv) & ALLOCATABLE_PV)) {
                        log_error("Physical volume \"%s\" is already "
                                  "allocatable", pv_name);
-                       r = 1;
-                       goto out;
+                       return 1;
                }
 
                if (!allocatable && !(pv_status(pv) & ALLOCATABLE_PV)) {
                        log_error("Physical volume \"%s\" is already "
                                  "unallocatable", pv_name);
-                       r = 1;
-                       goto out;
+                       return 1;
                }
 
                if (allocatable) {
@@ -104,50 +93,41 @@ static int _pvchange_single(struct cmd_context *cmd, struct volume_group *vg,
                                    "allocatable", pv_name);
                        pv->status &= ~ALLOCATABLE_PV;
                }
-       } else if (tagarg) {
-               /* tag or deltag */
+       }
 
-               dm_list_iterate_items(current_group, &cmd->arg_value_groups) {
-                       if (!grouped_arg_is_set(current_group->arg_values, tagarg))
-                               continue;
+       if (tagargs) {
+               /* tag or deltag */
+               if (arg_count(cmd, addtag_ARG) && !change_tag(cmd, NULL, NULL, pv, addtag_ARG))
+                       return_0;
 
-                       if (!(tag = grouped_arg_str_value(current_group->arg_values, tagarg, NULL))) {
-                               log_error("Failed to get tag");
-                               goto out;
-                       }
+               if (arg_count(cmd, deltag_ARG) && !change_tag(cmd, NULL, NULL, pv, deltag_ARG))
+                       return_0;
+       }
 
-                       if ((tagarg == addtag_ARG)) {
-                               if (!str_list_add(cmd->mem, &pv->tags, tag)) {
-                                       log_error("Failed to add tag %s to physical "
-                                                 "volume %s", tag, pv_name);
-                                       goto out;
-                               }
-                       } else if (!str_list_del(&pv->tags, tag)) {
-                               log_error("Failed to remove tag %s from "
-                                       "physical volume" "%s", tag, pv_name);
-                               goto out;
-                       }
-               }
-       } else if (arg_count(cmd, metadataignore_ARG)) {
+       if (arg_count(cmd, metadataignore_ARG)) {
                if ((vg_mda_copies(vg) != VGMETADATACOPIES_UNMANAGED) &&
                    (arg_count(cmd, force_ARG) == PROMPT) &&
                    yes_no_prompt("Override preferred number of copies "
                                  "of VG %s metadata? [y/n]: ",
                                  pv_vg_name(pv)) == 'n') {
                        log_error("Physical volume %s not changed", pv_name);
-                       goto out;
+                       return 0;
                }
                if (!pv_change_metadataignore(pv, mda_ignore))
-                       goto out;
-       } else {
+                       return_0;
+       } 
+
+       if (arg_count(cmd, uuid_ARG)) {
                /* --uuid: Change PV ID randomly */
+               memcpy(&pv->old_id, &pv->id, sizeof(pv->id));
                if (!id_create(&pv->id)) {
                        log_error("Failed to generate new random UUID for %s.",
                                  pv_name);
-                       goto out;
+                       return 0;
                }
                if (!id_write_format(&pv->id, uuid, sizeof(uuid)))
-                       goto_out;
+                       return 0;
                log_verbose("Changing uuid of %s to %s.", pv_name, uuid);
                if (!is_orphan(pv)) {
                        orig_vg_name = pv_vg_name(pv);
@@ -160,10 +140,10 @@ static int _pvchange_single(struct cmd_context *cmd, struct volume_group *vg,
 
                        pv->vg_name = pv->fmt->orphan_vg_name;
                        pv->pe_alloc_count = 0;
-                       if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) {
+                       if (!(pv_write(cmd, pv, 0))) {
                                log_error("pv_write with new uuid failed "
                                          "for %s.", pv_name);
-                               goto out;
+                               return 0;
                        }
                        pv->vg_name = orig_vg_name;
                        pv->pe_alloc_count = orig_pe_alloc_count;
@@ -179,20 +159,18 @@ static int _pvchange_single(struct cmd_context *cmd, struct volume_group *vg,
                if (!vg_write(vg) || !vg_commit(vg)) {
                        log_error("Failed to store physical volume \"%s\" in "
                                  "volume group \"%s\"", pv_name, vg->name);
-                       goto out;
+                       return 0;
                }
                backup(vg);
-       } else if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) {
+       } else if (!(pv_write(cmd, pv, 0))) {
                log_error("Failed to store physical volume \"%s\"",
                          pv_name);
-               goto out;
+               return 0;
        }
 
-       log_print("Physical volume \"%s\" changed", pv_name);
-       r = 1;
-out:
-       return r;
+       log_print_unless_silent("Physical volume \"%s\" changed", pv_name);
 
+       return 1;
 }
 
 int pvchange(struct cmd_context *cmd, int argc, char **argv)
@@ -209,11 +187,11 @@ int pvchange(struct cmd_context *cmd, int argc, char **argv)
        struct dm_list *vgnames;
        struct str_list *sll;
 
-       if (arg_count(cmd, allocatable_ARG) + arg_is_set(cmd, addtag_ARG) +
+       if (!(arg_count(cmd, allocatable_ARG) + arg_is_set(cmd, addtag_ARG) +
            arg_is_set(cmd, deltag_ARG) + arg_count(cmd, uuid_ARG) +
-           arg_count(cmd, metadataignore_ARG) != 1) {
-               log_error("Please give exactly one option of -x, -uuid, "
-                         "--addtag or --deltag");
+           arg_count(cmd, metadataignore_ARG))) {
+               log_error("Please give one or more of -x, -uuid, "
+                         "--addtag, --deltag or --metadataignore");
                return EINVALID_CMD_LINE;
        }
 
@@ -231,7 +209,7 @@ int pvchange(struct cmd_context *cmd, int argc, char **argv)
                log_verbose("Using physical volume(s) on command line");
                for (; opt < argc; opt++) {
                        pv_name = argv[opt];
-                       unescape_colons_and_at_signs(pv_name, NULL, NULL);
+                       dm_unescape_colons_and_at_signs(pv_name, NULL, NULL);
                        vg_name = find_vgname_from_pvname(cmd, pv_name);
                        if (!vg_name) {
                                log_error("Failed to read physical volume %s",
@@ -240,7 +218,7 @@ int pvchange(struct cmd_context *cmd, int argc, char **argv)
                        }
                        vg = vg_read_for_update(cmd, vg_name, NULL, 0);
                        if (vg_read_error(vg)) {
-                               free_vg(vg);
+                               release_vg(vg);
                                stack;
                                continue;
                        }
@@ -254,7 +232,7 @@ int pvchange(struct cmd_context *cmd, int argc, char **argv)
                        total++;
                        done += _pvchange_single(cmd, vg,
                                                 pvl->pv, NULL);
-                       unlock_and_free_vg(cmd, vg, vg_name);
+                       unlock_and_release_vg(cmd, vg, vg_name);
                }
        } else {
                log_verbose("Scanning for physical volume names");
@@ -275,7 +253,7 @@ int pvchange(struct cmd_context *cmd, int argc, char **argv)
                        dm_list_iterate_items(sll, vgnames) {
                                vg = vg_read_for_update(cmd, sll->str, NULL, 0);
                                if (vg_read_error(vg)) {
-                                       free_vg(vg);
+                                       release_vg(vg);
                                        stack;
                                        continue;
                                }
@@ -285,16 +263,16 @@ int pvchange(struct cmd_context *cmd, int argc, char **argv)
                                                                 pvl->pv,
                                                                 NULL);
                                }
-                               unlock_and_free_vg(cmd, vg, sll->str);
+                               unlock_and_release_vg(cmd, vg, sll->str);
                        }
                }
+               unlock_vg(cmd, VG_GLOBAL);
        }
 
-       unlock_vg(cmd, VG_GLOBAL);
-       log_print("%d physical volume%s changed / %d physical volume%s "
-                 "not changed",
-                 done, done == 1 ? "" : "s",
-                 total - done, (total - done) == 1 ? "" : "s");
+       log_print_unless_silent("%d physical volume%s changed / %d physical volume%s "
+                               "not changed",
+                               done, done == 1 ? "" : "s",
+                               total - done, (total - done) == 1 ? "" : "s");
 
        return (total == done) ? ECMD_PROCESSED : ECMD_FAILED;
 }
index 2ec75976f2f55342054cd4999b4bbac8936b2fa8..e45e77af6f8c89250f9b0956a1ebcbcd195621ff 100644 (file)
@@ -31,7 +31,7 @@ int pvck(struct cmd_context *cmd, int argc, char **argv)
                /* FIXME: warning and/or check if in use? */
                log_verbose("Scanning %s", argv[i]);
 
-               unescape_colons_and_at_signs(argv[i], NULL, NULL);
+               dm_unescape_colons_and_at_signs(argv[i], NULL, NULL);
                pv_analyze(cmd, argv[i],
                           arg_uint64_value(cmd, labelsector_ARG,
                                           UINT64_C(0)));
index a955d37370a9a9d1541cc7881995bf960c366b5d..5c12acbc12bc1745b4b11678950fac7f02742934 100644 (file)
@@ -56,6 +56,7 @@ static int pvcreate_restore_params_validate(struct cmd_context *cmd,
                if (!id_read_format(&pp->id, uuid))
                        return 0;
                pp->idp = &pp->id;
+               lvmcache_seed_infos_from_lvmetad(cmd); /* need to check for UUID dups */
        }
 
        if (arg_count(cmd, restorefile_ARG)) {
@@ -74,10 +75,10 @@ static int pvcreate_restore_params_validate(struct cmd_context *cmd,
                pp->pe_start = pv_pe_start(existing_pvl->pv);
                pp->extent_size = pv_pe_size(existing_pvl->pv);
                pp->extent_count = pv_pe_count(existing_pvl->pv);
-               free_vg(vg);
+               release_vg(vg);
        }
 
-       if (arg_sign_value(cmd, physicalvolumesize_ARG, 0) == SIGN_MINUS) {
+       if (arg_sign_value(cmd, physicalvolumesize_ARG, SIGN_NONE) == SIGN_MINUS) {
                log_error("Physical volume size may not be negative");
                return 0;
        }
@@ -93,6 +94,7 @@ int pvcreate(struct cmd_context *cmd, int argc, char **argv)
        int i;
        int ret = ECMD_PROCESSED;
        struct pvcreate_params pp;
+       struct physical_volume *pv;
 
        pvcreate_params_set_defaults(&pp);
 
@@ -109,9 +111,9 @@ int pvcreate(struct cmd_context *cmd, int argc, char **argv)
                        return ECMD_FAILED;
                }
 
-               unescape_colons_and_at_signs(argv[i], NULL, NULL);
+               dm_unescape_colons_and_at_signs(argv[i], NULL, NULL);
 
-               if (!pvcreate_single(cmd, argv[i], &pp)) {
+               if (!(pv = pvcreate_single(cmd, argv[i], &pp, 1))) {
                        stack;
                        ret = ECMD_FAILED;
                }
index 1ae0339ab60fafe5d65778c99e0d92c9b7241cf3..c6cd4129cd3c415655b7d8b32522a92f5932ba9d 100644 (file)
@@ -32,7 +32,7 @@ static int _pvdisplay_single(struct cmd_context *cmd,
                vg = vg_read(cmd, vg_name, (char *)&pv->vgid, 0);
                if (vg_read_error(vg)) {
                        log_error("Skipping volume group %s", vg_name);
-                       free_vg(vg);
+                       release_vg(vg);
                        /* FIXME If CLUSTERED should return ECMD_PROCESSED here */
                        return ECMD_FAILED;
                }
@@ -54,7 +54,7 @@ static int _pvdisplay_single(struct cmd_context *cmd,
        if (is_orphan(pv))
                size = pv_size(pv);
        else
-               size = (pv_pe_count(pv) - pv_pe_alloc_count(pv)) *
+               size = (uint64_t)(pv_pe_count(pv) - pv_pe_alloc_count(pv)) *
                        pv_pe_size(pv);
 
        if (arg_count(cmd, short_ARG)) {
@@ -85,7 +85,7 @@ out:
        if (vg_name)
                unlock_vg(cmd, vg_name);
        if (!old_vg)
-               free_vg(vg);
+               release_vg(vg);
 
        return ret;
 }
index 51f442fabba7d8a367dc843fd3804e7c638ef985..9649f119461f47f01446501083202d84d09bd550 100644 (file)
@@ -18,6 +18,7 @@
 #include "display.h"
 
 #define PVMOVE_FIRST_TIME   0x00000001      /* Called for first time */
+#define PVMOVE_EXCLUSIVE    0x00000002      /* Require exclusive LV */
 
 static int _pvmove_target_present(struct cmd_context *cmd, int clustered)
 {
@@ -121,7 +122,7 @@ static struct dm_list *_get_allocatable_pvs(struct cmd_context *cmd, int argc,
                }
 
                /* Remove PV if full */
-               if ((pvl->pv->pe_count == pvl->pv->pe_alloc_count))
+               if (pvl->pv->pe_count == pvl->pv->pe_alloc_count)
                        dm_list_del(&pvl->list);
        }
 
@@ -174,13 +175,16 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
                                                const char *lv_name,
                                                struct dm_list *allocatable_pvs,
                                                alloc_policy_t alloc,
-                                               struct dm_list **lvs_changed)
+                                               struct dm_list **lvs_changed,
+                                               unsigned *exclusive)
 {
        struct logical_volume *lv_mirr, *lv;
        struct lv_list *lvl;
        uint32_t log_count = 0;
        int lv_found = 0;
        int lv_skipped = 0;
+       int lv_active_count = 0;
+       int lv_exclusive_count = 0;
 
        /* FIXME Cope with non-contiguous => splitting existing segments */
        if (!(lv_mirr = lv_create_empty("pvmove%d", NULL,
@@ -202,7 +206,7 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
        /* Find segments to be moved and set up mirrors */
        dm_list_iterate_items(lvl, &vg->lvs) {
                lv = lvl->lv;
-               if ((lv == lv_mirr))
+               if (lv == lv_mirr)
                        continue;
                if (lv_name) {
                        if (strcmp(lv->name, lv_name))
@@ -211,29 +215,45 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
                }
                if (lv_is_origin(lv) || lv_is_cow(lv)) {
                        lv_skipped = 1;
-                       log_print("Skipping snapshot-related LV %s", lv->name);
+                       log_print_unless_silent("Skipping snapshot-related LV %s", lv->name);
                        continue;
                }
                if (lv->status & MIRRORED) {
                        lv_skipped = 1;
-                       log_print("Skipping mirror LV %s", lv->name);
+                       log_print_unless_silent("Skipping mirror LV %s", lv->name);
                        continue;
                }
                if (lv->status & MIRROR_LOG) {
                        lv_skipped = 1;
-                       log_print("Skipping mirror log LV %s", lv->name);
+                       log_print_unless_silent("Skipping mirror log LV %s", lv->name);
                        continue;
                }
                if (lv->status & MIRROR_IMAGE) {
                        lv_skipped = 1;
-                       log_print("Skipping mirror image LV %s", lv->name);
+                       log_print_unless_silent("Skipping mirror image LV %s", lv->name);
                        continue;
                }
                if (lv->status & LOCKED) {
                        lv_skipped = 1;
-                       log_print("Skipping locked LV %s", lv->name);
+                       log_print_unless_silent("Skipping locked LV %s", lv->name);
                        continue;
                }
+
+               if (vg_is_clustered(vg) &&
+                   lv_is_active_exclusive_remotely(lv)) {
+                       lv_skipped = 1;
+                       log_print_unless_silent("Skipping LV %s which is activated "
+                                               "exclusively on remote node.", lv->name);
+                       continue;
+               }
+
+               if (vg_is_clustered(vg)) {
+                       if (lv_is_active_exclusive_locally(lv))
+                               lv_exclusive_count++;
+                       else if (lv_is_active(lv))
+                               lv_active_count++;
+               }
+
                if (!_insert_pvmove_mirrors(cmd, lv_mirr, source_pvl, lv,
                                            *lvs_changed))
                        return_NULL;
@@ -254,6 +274,25 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
                return NULL;
        }
 
+       if (vg_is_clustered(vg) && lv_active_count && *exclusive) {
+               log_error("Cannot move in clustered VG %s, "
+                         "clustered mirror (cmirror) not detected "
+                         "and LVs are activated non-exclusively.",
+                         vg->name);
+               return NULL;
+       }
+
+       if (vg_is_clustered(vg) && lv_exclusive_count) {
+               if (lv_active_count) {
+                       log_error("Cannot move in clustered VG %s "
+                                 "if some LVs are activated "
+                                 "exclusively while others don't.",
+                                 vg->name);
+                       return NULL;
+               }
+               *exclusive = 1;
+       }
+
        if (!lv_add_mirrors(cmd, lv_mirr, 1, 1, 0, 0, log_count,
                            allocatable_pvs, alloc, MIRROR_BY_SEG)) {
                log_error("Failed to convert pvmove LV to mirrored");
@@ -273,7 +312,7 @@ static int _activate_lv(struct cmd_context *cmd, struct logical_volume *lv_mirr,
 {
        int r = 0;
 
-       if (exclusive)
+       if (exclusive || lv_is_active_exclusive(lv_mirr))
                r = activate_lv_excl(cmd, lv_mirr);
        else
                r = activate_lv(cmd, lv_mirr);
@@ -305,11 +344,60 @@ static int _detach_pvmove_mirror(struct cmd_context *cmd,
        return 1;
 }
 
+static int _suspend_lvs(struct cmd_context *cmd, unsigned first_time,
+                       struct logical_volume *lv_mirr,
+                       struct dm_list *lvs_changed,
+                       struct volume_group *vg_to_revert)
+{
+       /*
+        * Suspend lvs_changed the first time.
+        * Suspend mirrors on subsequent calls.
+        */
+       if (first_time) {
+               if (!suspend_lvs(cmd, lvs_changed, vg_to_revert))
+                       return_0;
+       } else if (!suspend_lv(cmd, lv_mirr)) {
+               if (vg_to_revert)
+                       vg_revert(vg_to_revert);
+               return_0;
+       }
+
+       return 1;
+}
+
+static int _resume_lvs(struct cmd_context *cmd, unsigned first_time,
+                      struct logical_volume *lv_mirr,
+                      struct dm_list *lvs_changed)
+{
+       /*
+        * Suspend lvs_changed the first time.
+        * Suspend mirrors on subsequent calls.
+        */
+
+       if (first_time) {
+               if (!resume_lvs(cmd, lvs_changed)) {
+                       log_error("Unable to resume logical volumes");
+                       return 0;
+               }
+       } else if (!resume_lv(cmd, lv_mirr)) {
+               log_error("Unable to reactivate logical volume \"%s\"",
+                         lv_mirr->name);
+               return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * Called to set up initial pvmove LV and to advance the mirror
+ * to successive sections of it.
+ * (Not called after the last section completes.)
+ */
 static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg,
                            struct logical_volume *lv_mirr,
                            struct dm_list *lvs_changed, unsigned flags)
 {
-       unsigned exclusive = _pvmove_is_exclusive(cmd, vg);
+       unsigned exclusive = (flags & PVMOVE_EXCLUSIVE) ? 1 : 0;
        unsigned first_time = (flags & PVMOVE_FIRST_TIME) ? 1 : 0;
        int r = 0;
 
@@ -319,38 +407,31 @@ static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg,
                return 0;
        }
 
-       /* Suspend lvs_changed */
-       if (!suspend_lvs(cmd, lvs_changed)) {
-               vg_revert(vg);
-               goto_out;
-       }
-
-       /* Suspend mirrors on subsequent calls */
-       if (!first_time) {
-               if (!suspend_lv(cmd, lv_mirr)) {
-                       if (!resume_lvs(cmd, lvs_changed))
-                               stack;
-                       vg_revert(vg);
-                       goto_out;
-               }
+       if (!_suspend_lvs(cmd, first_time, lv_mirr, lvs_changed, vg)) {
+               log_error("ABORTING: Temporary pvmove mirror %s failed.", first_time ? "activation" : "reload");
+               /* FIXME Add a recovery path for first time too. */
+               if (!first_time && !revert_lv(cmd, lv_mirr))
+                       stack;
+               return 0;
        }
 
        /* Commit on-disk metadata */
        if (!vg_commit(vg)) {
                log_error("ABORTING: Volume group metadata update failed.");
-               if (!first_time)
-                       if (!resume_lv(cmd, lv_mirr))
-                               stack;
-               if (!resume_lvs(cmd, lvs_changed))
+               if (!_resume_lvs(cmd, first_time, lv_mirr, lvs_changed))
+                       stack;
+               if (!first_time && !revert_lv(cmd, lv_mirr))
                        stack;
-               vg_revert(vg);
-               goto out;
+               return 0;
        }
 
        /* Activate the temporary mirror LV */
        /* Only the first mirror segment gets activated as a mirror */
        /* FIXME: Add option to use a log */
        if (first_time) {
+               if (!exclusive && _pvmove_is_exclusive(cmd, vg))
+                       exclusive = 1;
+
                if (!_activate_lv(cmd, lv_mirr, exclusive)) {
                        if (test_mode()) {
                                r = 1;
@@ -358,46 +439,22 @@ static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg,
                        }
 
                        /*
-                        * FIXME: review ordering of operations above,
-                        * temporary mirror should be preloaded in suspend.
-                        * Also banned operation here when suspended.
-                        * Nothing changed yet, try to revert pvmove.
+                        * FIXME Run --abort internally here.
                         */
-                       log_error("Temporary pvmove mirror activation failed.");
-
-                       /* Ensure that temporary mrror is deactivate even on other nodes. */
-                       (void)deactivate_lv(cmd, lv_mirr);
-
-                       /* Revert metadata */
-                       if (!_detach_pvmove_mirror(cmd, lv_mirr) ||
-                           !lv_remove(lv_mirr) ||
-                           !vg_write(vg) || !vg_commit(vg))
-                               log_error("ABORTING: Restoring original configuration "
-                                         "before pvmove failed. Run pvmove --abort.");
-
-                       /* Unsuspend LVs */
-                       if(!resume_lvs(cmd, lvs_changed))
-                               stack;
-
-                       goto out;
+                       log_error("ABORTING: Temporary pvmove mirror activation failed. Run pvmove --abort.");
+                       goto_out;
                }
-       } else if (!resume_lv(cmd, lv_mirr)) {
-               log_error("Unable to reactivate logical volume \"%s\"",
-                         lv_mirr->name);
-               if (!resume_lvs(cmd, lvs_changed))
-                       stack;
-               goto out;
-       }
-
-       /* Unsuspend LVs */
-       if (!resume_lvs(cmd, lvs_changed)) {
-               log_error("Unable to resume logical volumes");
-               goto out;
        }
 
        r = 1;
+
 out:
-       backup(vg);
+       if (!_resume_lvs(cmd, first_time, lv_mirr, lvs_changed))
+               r = 0;
+
+       if (r)
+               backup(vg);
+
        return r;
 }
 
@@ -413,7 +470,7 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
        struct dm_list *lvs_changed;
        struct physical_volume *pv;
        struct logical_volume *lv_mirr;
-       unsigned first_time = 1;
+       unsigned flags = PVMOVE_FIRST_TIME;
        unsigned exclusive;
        int r = ECMD_FAILED;
 
@@ -431,11 +488,13 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
                if (!(lv_name = _extract_lvname(cmd, pv_vg_name(pv),
                                                arg_value(cmd, name_ARG)))) {
                        stack;
+                       free_pv_fid(pv);
                        return EINVALID_CMD_LINE;
                }
 
                if (!validate_name(lv_name)) {
                        log_error("Logical volume name %s is invalid", lv_name);
+                       free_pv_fid(pv);
                        return EINVALID_CMD_LINE;
                }
        }
@@ -445,7 +504,7 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
 
        vg = _get_vg(cmd, pv_vg_name(pv));
        if (vg_read_error(vg)) {
-               free_vg(vg);
+               release_vg(vg);
                stack;
                return ECMD_FAILED;
        }
@@ -453,7 +512,7 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
        exclusive = _pvmove_is_exclusive(cmd, vg);
 
        if ((lv_mirr = find_pvmove_lv(vg, pv_dev(pv), PVMOVE))) {
-               log_print("Detected pvmove in progress for %s", pv_name);
+               log_print_unless_silent("Detected pvmove in progress for %s", pv_name);
                if (argc || lv_name)
                        log_error("Ignoring remaining command line arguments");
 
@@ -468,14 +527,14 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
                        goto out;
                }
 
-               first_time = 0;
+               flags &= ~PVMOVE_FIRST_TIME;
        } else {
                /* Determine PE ranges to be moved */
                if (!(source_pvl = create_pv_list(cmd->mem, vg, 1,
                                                  &pv_name_arg, 0)))
                        goto_out;
 
-               alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
+               alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
                if (alloc == ALLOC_INHERIT)
                        alloc = vg->alloc;
 
@@ -489,7 +548,7 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
 
                if (!(lv_mirr = _set_up_pvmove_lv(cmd, vg, source_pvl, lv_name,
                                                  allocatable_pvs, alloc,
-                                                 &lvs_changed)))
+                                                 &lvs_changed, &exclusive)))
                        goto_out;
        }
 
@@ -501,16 +560,19 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
        /* init_pvmove(1); */
        /* vg->status |= PVMOVE; */
 
-       if (first_time) {
+       if (flags & PVMOVE_FIRST_TIME) {
+               if (exclusive)
+                       flags |= PVMOVE_EXCLUSIVE;
                if (!_update_metadata
-                   (cmd, vg, lv_mirr, lvs_changed, PVMOVE_FIRST_TIME))
+                   (cmd, vg, lv_mirr, lvs_changed, flags))
                        goto_out;
        }
 
        /* LVs are all in status LOCKED */
        r = ECMD_PROCESSED;
 out:
-       unlock_and_free_vg(cmd, vg, pv_vg_name(pv));
+       free_pv_fid(pv);
+       unlock_and_release_vg(cmd, vg, pv_vg_name(pv));
        return r;
 }
 
@@ -521,7 +583,8 @@ static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg,
        int r = 1;
 
        if (!dm_list_empty(lvs_changed) &&
-           !_detach_pvmove_mirror(cmd, lv_mirr)) {
+           (!_detach_pvmove_mirror(cmd, lv_mirr) ||
+           !replace_lv_with_error_segment(lv_mirr))) {
                log_error("ABORTING: Removal of temporary mirror failed");
                return 0;
        }
@@ -533,26 +596,21 @@ static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg,
                return 0;
        }
 
-       /* Suspend LVs changed */
-       if (!suspend_lvs(cmd, lvs_changed)) {
-               log_error("Locking LVs to remove temporary mirror failed");
-               r = 0;
-       }
-
-       /* Suspend mirror LV to flush pending I/O */
-       if (!suspend_lv(cmd, lv_mirr)) {
-               log_error("Suspension of temporary mirror LV failed");
-               r = 0;
+       /* Suspend LVs changed (implicitly suspends lv_mirr) */
+       if (!suspend_lvs(cmd, lvs_changed, vg)) {
+               log_error("ABORTING: Locking LVs to remove temporary mirror failed");
+               if (!revert_lv(cmd, lv_mirr))
+                       stack;
+               return 0;
        }
 
        /* Store metadata without dependencies on mirror segments */
        if (!vg_commit(vg)) {
                log_error("ABORTING: Failed to write new data locations "
                          "to disk.");
-               vg_revert(vg);
-               if (!resume_lv(cmd, lv_mirr))
+               if (!revert_lv(cmd, lv_mirr))
                        stack;
-               if (!resume_lvs(cmd, lvs_changed))
+               if (!revert_lvs(cmd, lvs_changed))
                        stack;
                return 0;
        }
@@ -600,6 +658,7 @@ static struct volume_group *_get_move_vg(struct cmd_context *cmd,
                                         const char *uuid __attribute__((unused)))
 {
        struct physical_volume *pv;
+       struct volume_group *vg;
 
        /* Reread all metadata in case it got changed */
        if (!(pv = find_pv_by_name(cmd, name))) {
@@ -608,7 +667,10 @@ static struct volume_group *_get_move_vg(struct cmd_context *cmd,
                return NULL;
        }
 
-       return _get_vg(cmd, pv_vg_name(pv));
+       vg = _get_vg(cmd, pv_vg_name(pv));
+       free_pv_fid(pv);
+
+       return vg;
 }
 
 static struct poll_functions _pvmove_fns = {
@@ -649,7 +711,7 @@ int pvmove(struct cmd_context *cmd, int argc, char **argv)
                        return ECMD_FAILED;
                }
 
-               unescape_colons_and_at_signs(pv_name, &colon, NULL);
+               dm_unescape_colons_and_at_signs(pv_name, &colon, NULL);
 
                /* Drop any PE lists from PV name */
                if (colon)
index a8717e05cd2ea145c6cf8f305f985249565c9ce1..823c069d0ee3cd977091979ccac4114f7606d12a 100644 (file)
@@ -25,15 +25,12 @@ const char _really_wipe[] =
 static int pvremove_check(struct cmd_context *cmd, const char *name)
 {
        struct physical_volume *pv;
-       struct dm_list mdas;
-
-       dm_list_init(&mdas);
 
        /* FIXME Check partition type is LVM unless --force is given */
 
        /* Is there a pv here already? */
        /* If not, this is an error unless you used -f. */
-       if (!(pv = pv_read(cmd, name, &mdas, NULL, 1, 0))) {
+       if (!(pv = pv_read(cmd, name, 1, 0))) {
                if (arg_count(cmd, force_ARG))
                        return 1;
                log_error("Physical Volume %s not found", name);
@@ -47,35 +44,39 @@ static int pvremove_check(struct cmd_context *cmd, const char *name)
         * means checking every VG by scanning every
         * PV on the system.
         */
-       if (is_orphan(pv) && !dm_list_size(&mdas)) {
+       if (is_orphan(pv) && !dm_list_size(&pv->fid->metadata_areas_in_use) &&
+           !dm_list_size(&pv->fid->metadata_areas_ignored)) {
                if (!scan_vgs_for_pvs(cmd, 0)) {
                        log_error("Rescan for PVs without metadata areas "
                                  "failed.");
-                       return 0;
+                       goto bad;
                }
-               if (!(pv = pv_read(cmd, name, NULL, NULL, 1, 0))) {
+               free_pv_fid(pv);
+               if (!(pv = pv_read(cmd, name, 1, 0))) {
                        log_error("Failed to read physical volume %s", name);
-                       return 0;
+                       goto bad;
                }
        }
 
        /* orphan ? */
-       if (is_orphan(pv))
+       if (is_orphan(pv)) {
+               free_pv_fid(pv);
                return 1;
+       }
 
        /* Allow partial & exported VGs to be destroyed. */
        /* we must have -ff to overwrite a non orphan */
        if (arg_count(cmd, force_ARG) < 2) {
-               log_error("Can't pvremove physical volume \"%s\" of "
-                         "volume group \"%s\" without -ff", name, pv_vg_name(pv));
-               return 0;
+               log_error("PV %s belongs to Volume Group %s so please use vgreduce first.", name, pv_vg_name(pv));
+               log_error("(If you are certain you need pvremove, then confirm by using --force twice.)");
+               goto bad;
        }
 
        /* prompt */
        if (!arg_count(cmd, yes_ARG) &&
            yes_no_prompt(_really_wipe, name, pv_vg_name(pv)) == 'n') {
                log_error("%s: physical volume label not removed", name);
-               return 0;
+               goto bad;
        }
 
        if (arg_count(cmd, force_ARG)) {
@@ -86,7 +87,12 @@ static int pvremove_check(struct cmd_context *cmd, const char *name)
                          !is_orphan(pv) ? "\"" : "");
        }
 
+       free_pv_fid(pv);
        return 1;
+
+bad:
+       free_pv_fid(pv);
+       return 0;
 }
 
 static int pvremove_single(struct cmd_context *cmd, const char *pv_name,
@@ -101,33 +107,36 @@ static int pvremove_single(struct cmd_context *cmd, const char *pv_name,
        }
 
        if (!pvremove_check(cmd, pv_name))
-               goto error;
+               goto out;
 
        if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
                log_error("%s: Couldn't find device.  Check your filters?",
                          pv_name);
-               goto error;
+               goto out;
        }
 
        if (!dev_test_excl(dev)) {
                /* FIXME Detect whether device-mapper is still using the device */
                log_error("Can't open %s exclusively - not removing. "
                          "Mounted filesystem?", dev_name(dev));
-               goto error;
+               goto out;
        }
 
        /* Wipe existing label(s) */
        if (!label_remove(dev)) {
                log_error("Failed to wipe existing label(s) on %s", pv_name);
-               goto error;
+               goto out;
        }
 
-       log_print("Labels on physical volume \"%s\" successfully wiped",
-                 pv_name);
+       if (!lvmetad_pv_gone_by_dev(dev, NULL))
+               goto_out;
+
+       log_print_unless_silent("Labels on physical volume \"%s\" successfully wiped",
+                               pv_name);
 
        ret = ECMD_PROCESSED;
 
-      error:
+out:
        unlock_vg(cmd, VG_ORPHANS);
 
        return ret;
@@ -144,7 +153,7 @@ int pvremove(struct cmd_context *cmd, int argc, char **argv)
        }
 
        for (i = 0; i < argc; i++) {
-               unescape_colons_and_at_signs(argv[i], NULL, NULL);
+               dm_unescape_colons_and_at_signs(argv[i], NULL, NULL);
                r = pvremove_single(cmd, argv[i], NULL);
                if (r > ret)
                        ret = r;
index 8582ef429f67d80dc2e14891ac2ed9145687e257..2f0693aa3c87441751bdfe39addef6b52270cc14 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include "tools.h"
+#include "metadata.h"
 
 struct pvresize_params {
        uint64_t new_size;
@@ -30,16 +31,11 @@ static int _pv_resize_single(struct cmd_context *cmd,
 {
        struct pv_list *pvl;
        uint64_t size = 0;
-       uint32_t new_pe_count = 0;
        int r = 0;
-       struct dm_list mdas;
        const char *pv_name = pv_dev_name(pv);
        const char *vg_name = pv_vg_name(pv);
-       struct lvmcache_info *info;
-       int mda_count = 0;
        struct volume_group *old_vg = vg;
-
-       dm_list_init(&mdas);
+       int vg_needs_pv_write = 0;
 
        if (is_orphan_vg(vg_name)) {
                if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
@@ -47,18 +43,16 @@ static int _pv_resize_single(struct cmd_context *cmd,
                        return 0;
                }
 
-               if (!(pv = pv_read(cmd, pv_name, &mdas, NULL, 1, 0))) {
+               if (!(pv = pv_read(cmd, pv_name, 1, 0))) {
                        unlock_vg(cmd, vg_name);
                        log_error("Unable to read PV \"%s\"", pv_name);
                        return 0;
                }
-
-               mda_count = dm_list_size(&mdas);
        } else {
                vg = vg_read_for_update(cmd, vg_name, NULL, 0);
 
                if (vg_read_error(vg)) {
-                       free_vg(vg);
+                       release_vg(vg);
                        log_error("Unable to read volume group \"%s\".",
                                  vg_name);
                        return 0;
@@ -72,24 +66,10 @@ static int _pv_resize_single(struct cmd_context *cmd,
 
                pv = pvl->pv;
 
-               if (!(info = info_from_pvid(pv->dev->pvid, 0))) {
-                       log_error("Can't get info for PV %s in volume group %s",
-                                 pv_name, vg->name);
-                       goto out;
-               }
-
-               mda_count = dm_list_size(&info->mdas);
-
                if (!archive(vg))
                        goto out;
        }
 
-       /* FIXME Create function to test compatibility properly */
-       if (mda_count > 1) {
-               log_error("%s: too many metadata areas for pvresize", pv_name);
-               goto out;
-       }
-
        if (!(pv->fmt->features & FMT_RESIZE_PV)) {
                log_error("Physical volume %s format does not support resizing.",
                          pv_name);
@@ -111,40 +91,24 @@ static int _pv_resize_single(struct cmd_context *cmd,
                size = new_size;
        }
 
-       if (size < PV_MIN_SIZE) {
-               log_error("%s: Size must exceed minimum of %ld sectors.",
-                         pv_name, PV_MIN_SIZE);
-               goto out;
-       }
-
-       if (size < pv_pe_start(pv)) {
-               log_error("%s: Size must exceed physical extent start of "
-                         "%" PRIu64 " sectors.", pv_name, pv_pe_start(pv));
-               goto out;
-       }
-
-       pv->size = size;
+       log_verbose("Resizing volume \"%s\" to %" PRIu64 " sectors.",
+                   pv_name, pv_size(pv));
 
-       if (vg) {
-               pv->size -= pv_pe_start(pv);
-               new_pe_count = pv_size(pv) / vg->extent_size;
+       if (!pv_resize(pv, vg, size))
+               goto_out;
 
-               if (!new_pe_count) {
-                       log_error("%s: Size must leave space for at "
-                                 "least one physical extent of "
-                                 "%" PRIu32 " sectors.", pv_name,
-                                 pv_pe_size(pv));
-                       goto out;
-               }
+       log_verbose("Updating physical volume \"%s\"", pv_name);
 
-               if (!pv_resize(pv, vg, new_pe_count))
-                       goto_out;
+       /* Write PV label only if this an orphan PV or it has 2nd mda. */
+       if ((is_orphan_vg(vg_name) ||
+            (vg_needs_pv_write = (fid_get_mda_indexed(vg->fid,
+                       (const char *) &pv->id, ID_LEN, 1) != NULL))) &&
+           !pv_write(cmd, pv, 1)) {
+               log_error("Failed to store physical volume \"%s\"",
+                         pv_name);
+               goto out;
        }
 
-       log_verbose("Resizing volume \"%s\" to %" PRIu64 " sectors.",
-                   pv_name, pv_size(pv));
-
-       log_verbose("Updating physical volume \"%s\"", pv_name);
        if (!is_orphan_vg(vg_name)) {
                if (!vg_write(vg) || !vg_commit(vg)) {
                        log_error("Failed to store physical volume \"%s\" in "
@@ -152,19 +116,20 @@ static int _pv_resize_single(struct cmd_context *cmd,
                        goto out;
                }
                backup(vg);
-       } else if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) {
-               log_error("Failed to store physical volume \"%s\"",
-                         pv_name);
-               goto out;
        }
 
-       log_print("Physical volume \"%s\" changed", pv_name);
+       log_print_unless_silent("Physical volume \"%s\" changed", pv_name);
        r = 1;
 
 out:
+       if (!r && vg_needs_pv_write)
+               log_error("Use pvcreate and vgcfgrestore "
+                         "to repair from archived metadata.");
        unlock_vg(cmd, vg_name);
+       if (is_orphan_vg(vg_name))
+               free_pv_fid(pv);
        if (!old_vg)
-               free_vg(vg);
+               release_vg(vg);
        return r;
 }
 
@@ -197,7 +162,7 @@ int pvresize(struct cmd_context *cmd, int argc, char **argv)
                return EINVALID_CMD_LINE;
        }
 
-       if (arg_sign_value(cmd, physicalvolumesize_ARG, 0) == SIGN_MINUS) {
+       if (arg_sign_value(cmd, physicalvolumesize_ARG, SIGN_NONE) == SIGN_MINUS) {
                log_error("Physical volume size may not be negative");
                return 0;
        }
@@ -211,8 +176,8 @@ int pvresize(struct cmd_context *cmd, int argc, char **argv)
        ret = process_each_pv(cmd, argc, argv, NULL, READ_FOR_UPDATE, 0, &params,
                              _pvresize_single);
 
-       log_print("%d physical volume(s) resized / %d physical volume(s) "
-                 "not resized", params.done, params.total - params.done);
+       log_print_unless_silent("%d physical volume(s) resized / %d physical volume(s) "
+                               "not resized", params.done, params.total - params.done);
 
        return ret;
 }
index b24b7ab51b8680bdbd5650a53e467b5bbe5d9ae1..3d5ddefd92cde64a8c9fa6e7527aa92890c4e569 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -15,6 +15,9 @@
 
 #include "tools.h"
 
+#include "lvmetad.h"
+#include "lvmcache.h"
+
 int pv_max_name_len = 0;
 int vg_max_name_len = 0;
 
@@ -25,13 +28,13 @@ static void _pvscan_display_single(struct cmd_context *cmd,
        char uuid[64] __attribute__((aligned(8)));
        unsigned vg_name_len = 0;
 
-       char pv_tmp_name[NAME_LEN] = { 0, };
-       char vg_tmp_name[NAME_LEN] = { 0, };
-       char vg_name_this[NAME_LEN] = { 0, };
+       char pv_tmp_name[NAME_LEN] = { 0 };
+       char vg_tmp_name[NAME_LEN] = { 0 };
+       char vg_name_this[NAME_LEN] = { 0 };
 
        /* short listing? */
        if (arg_count(cmd, short_ARG) > 0) {
-               log_print("%s", pv_dev_name(pv));
+               log_print_unless_silent("%s", pv_dev_name(pv));
                return;
        }
 
@@ -46,8 +49,6 @@ static void _pvscan_display_single(struct cmd_context *cmd,
                /* return; */
        }
 
-       memset(pv_tmp_name, 0, sizeof(pv_tmp_name));
-
        vg_name_len = strlen(pv_vg_name(pv)) + 1;
 
        if (arg_count(cmd, uuid_ARG)) {
@@ -63,41 +64,156 @@ static void _pvscan_display_single(struct cmd_context *cmd,
        }
 
        if (is_orphan(pv)) {
-               log_print("PV %-*s    %-*s %s [%s]",
-                         pv_max_name_len, pv_tmp_name,
-                         vg_max_name_len, " ",
-                         pv->fmt ? pv->fmt->name : "    ",
-                         display_size(cmd, pv_size(pv)));
+               log_print_unless_silent("PV %-*s    %-*s %s [%s]",
+                                       pv_max_name_len, pv_tmp_name,
+                                       vg_max_name_len, " ",
+                                       pv->fmt ? pv->fmt->name : "    ",
+                                       display_size(cmd, pv_size(pv)));
                return;
        }
 
        if (pv_status(pv) & EXPORTED_VG) {
                strncpy(vg_name_this, pv_vg_name(pv), vg_name_len);
-               log_print("PV %-*s  is in exported VG %s "
-                         "[%s / %s free]",
-                         pv_max_name_len, pv_tmp_name,
-                         vg_name_this,
-                         display_size(cmd, (uint64_t) pv_pe_count(pv) *
-                                      pv_pe_size(pv)),
-                         display_size(cmd, (uint64_t) (pv_pe_count(pv) -
-                                               pv_pe_alloc_count(pv))
-                                      * pv_pe_size(pv)));
+               log_print_unless_silent("PV %-*s  is in exported VG %s "
+                                       "[%s / %s free]",
+                                       pv_max_name_len, pv_tmp_name,
+                                       vg_name_this,
+                                       display_size(cmd, (uint64_t) pv_pe_count(pv) * pv_pe_size(pv)),
+                                       display_size(cmd, (uint64_t) (pv_pe_count(pv) - pv_pe_alloc_count(pv)) * pv_pe_size(pv)));
                return;
        }
 
        sprintf(vg_tmp_name, "%s", pv_vg_name(pv));
-       log_print("PV %-*s VG %-*s %s [%s / %s free]", pv_max_name_len,
-                 pv_tmp_name, vg_max_name_len, vg_tmp_name,
-                 pv->fmt ? pv->fmt->name : "    ",
-                 display_size(cmd, (uint64_t) pv_pe_count(pv) *
-                                              pv_pe_size(pv)),
-                 display_size(cmd, (uint64_t) (pv_pe_count(pv) -
-                                               pv_pe_alloc_count(pv)) *
-                                          pv_pe_size(pv)));
+       log_print_unless_silent("PV %-*s VG %-*s %s [%s / %s free]", pv_max_name_len,
+                               pv_tmp_name, vg_max_name_len, vg_tmp_name,
+                               pv->fmt ? pv->fmt->name : "    ",
+                               display_size(cmd, (uint64_t) pv_pe_count(pv) * pv_pe_size(pv)),
+                               display_size(cmd, (uint64_t) (pv_pe_count(pv) - pv_pe_alloc_count(pv)) * pv_pe_size(pv)));
+}
+
+static int _auto_activation_handler(struct volume_group *vg, int partial,
+                                   activation_change_t activate)
+{
+       /* TODO: add support for partial and clustered VGs */
+       if (partial || vg_is_clustered(vg))
+               return 1;
+
+       if (!vgchange_activate(vg->cmd, vg, activate)) {
+               log_error("%s: autoactivation failed.", vg->name);
+               return 0;
+       }
+
+       return 1;
+}
+
+static int _pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv)
+{
+       int ret = ECMD_PROCESSED;
+       struct device *dev;
+       const char *pv_name;
+       int32_t major = -1;
+       int32_t minor = -1;
+       int devno_args = 0;
+       struct arg_value_group_list *current_group;
+       dev_t devno;
+       char *buf;
+       activation_handler handler = NULL;
+
+       if (arg_count(cmd, activate_ARG)) {
+               if (arg_uint_value(cmd, activate_ARG, CHANGE_AAY) != CHANGE_AAY) {
+                       log_error("Only --activate ay allowed with pvscan.");
+                       return 0;
+               }
+               handler = _auto_activation_handler;
+       }
+
+       if (arg_count(cmd, major_ARG) + arg_count(cmd, minor_ARG))
+               devno_args = 1;
+
+       if (devno_args && (!arg_count(cmd, major_ARG) || !arg_count(cmd, minor_ARG))) {
+               log_error("Both --major and --minor required to identify devices.");
+               return EINVALID_CMD_LINE;
+       }
+       
+       if (!lock_vol(cmd, VG_GLOBAL, LCK_VG_READ)) {
+               log_error("Unable to obtain global lock.");
+               return ECMD_FAILED;
+       }
+
+       /* Scan everything? */
+       if (!argc && !devno_args) {
+               if (!lvmetad_pvscan_all_devs(cmd, handler))
+                       ret = ECMD_FAILED;
+               goto out;
+       }
+
+       log_verbose("Using physical volume(s) on command line");
+
+       /* Process any command line PVs first. */
+       while (argc--) {
+               pv_name = *argv++;
+               dev = dev_cache_get(pv_name, NULL);
+               if (!dev) {
+                       log_error("Physical Volume %s not found.", pv_name);
+                       ret = ECMD_FAILED;
+                       continue;
+               }
+
+               if (!lvmetad_pvscan_single(cmd, dev, handler)) {
+                       ret = ECMD_FAILED;
+                       break;
+               }
+               if (sigint_caught())
+                       break;
+       }
+
+       if (!devno_args)
+               goto out;
+
+       /* Process any grouped --major --minor args */
+       dm_list_iterate_items(current_group, &cmd->arg_value_groups) {
+               major = grouped_arg_int_value(current_group->arg_values, major_ARG, major);
+               minor = grouped_arg_int_value(current_group->arg_values, minor_ARG, minor);
+
+               if (major < 0 || minor < 0)
+                       continue;
+
+               devno = MKDEV((dev_t)major, minor);
+
+               if (!(dev = dev_cache_get_by_devt(devno, NULL))) {
+                       if (!dm_asprintf(&buf, "%" PRIi32 ":%" PRIi32, major, minor))
+                               stack;
+                       /* FIXME Filters? */
+                       if (!lvmetad_pv_gone(devno, buf ? : "", handler)) {
+                               ret = ECMD_FAILED;
+                               if (buf)
+                                       dm_free(buf);
+                               break;
+                       }
+
+                       log_print_unless_silent("Device %s not found. "
+                                               "Cleared from lvmetad cache.", buf ? : "");
+                       if (buf)
+                               dm_free(buf);
+                       continue;
+               }
+
+               if (!lvmetad_pvscan_single(cmd, dev, handler)) {
+                       ret = ECMD_FAILED;
+                       break;
+               }
+
+               if (sigint_caught())
+                       break;
+       }
+
+out:
+       unlock_vg(cmd, VG_GLOBAL);
+
+       return ret;
 }
 
-int pvscan(struct cmd_context *cmd, int argc __attribute__((unused)),
-          char **argv __attribute__((unused)))
+int pvscan(struct cmd_context *cmd, int argc, char **argv)
 {
        int new_pvs_found = 0;
        int pvs_found = 0;
@@ -113,6 +229,19 @@ int pvscan(struct cmd_context *cmd, int argc __attribute__((unused)),
        pv_max_name_len = 0;
        vg_max_name_len = 0;
 
+       if (arg_count(cmd, cache_ARG))
+               return _pvscan_lvmetad(cmd, argc, argv);
+
+       if (arg_count(cmd, activate_ARG)) {
+               log_error("--activate is only valid with --cache.");
+               return EINVALID_CMD_LINE;
+       }
+
+       if (arg_count(cmd, major_ARG) + arg_count(cmd, minor_ARG)) {
+               log_error("--major and --minor are only valid with --cache.");
+               return EINVALID_CMD_LINE;
+       }
+
        if (arg_count(cmd, novolumegroup_ARG) && arg_count(cmd, exported_ARG)) {
                log_error("Options -e and -n are incompatible");
                return EINVALID_CMD_LINE;
@@ -128,9 +257,14 @@ int pvscan(struct cmd_context *cmd, int argc __attribute__((unused)),
                return ECMD_FAILED;
        }
 
-       persistent_filter_wipe(cmd->filter);
+       if (cmd->filter->wipe)
+               cmd->filter->wipe(cmd->filter);
        lvmcache_destroy(cmd, 1);
 
+       /* populate lvmcache */
+       if (!lvmetad_vg_list_to_lvmcache(cmd))
+               stack;
+
        log_verbose("Walking through all physical volumes");
        if (!(pvslist = get_pvs(cmd))) {
                unlock_vg(cmd, VG_GLOBAL);
@@ -143,9 +277,10 @@ int pvscan(struct cmd_context *cmd, int argc __attribute__((unused)),
                pv = pvl->pv;
 
                if ((arg_count(cmd, exported_ARG)
-                    && !(pv_status(pv) & EXPORTED_VG))
-                   || (arg_count(cmd, novolumegroup_ARG) && (!is_orphan(pv)))) {
+                    && !(pv_status(pv) & EXPORTED_VG)) ||
+                   (arg_count(cmd, novolumegroup_ARG) && (!is_orphan(pv)))) {
                        dm_list_del(&pvl->list);
+                       free_pv_fid(pv);
                        continue;
                }
 
@@ -183,21 +318,23 @@ int pvscan(struct cmd_context *cmd, int argc __attribute__((unused)),
        pv_max_name_len += 2;
        vg_max_name_len += 2;
 
-       dm_list_iterate_items(pvl, pvslist)
-           _pvscan_display_single(cmd, pvl->pv, NULL);
+       dm_list_iterate_items(pvl, pvslist) {
+               _pvscan_display_single(cmd, pvl->pv, NULL);
+               free_pv_fid(pvl->pv);
+       }
 
        if (!pvs_found) {
-               log_print("No matching physical volumes found");
+               log_print_unless_silent("No matching physical volumes found");
                unlock_vg(cmd, VG_GLOBAL);
                return ECMD_PROCESSED;
        }
 
-       log_print("Total: %d [%s] / in use: %d [%s] / in no VG: %d [%s]",
-                 pvs_found,
-                 display_size(cmd, size_total),
-                 pvs_found - new_pvs_found,
-                 display_size(cmd, (size_total - size_new)),
-                 new_pvs_found, display_size(cmd, size_new));
+       log_print_unless_silent("Total: %d [%s] / in use: %d [%s] / in no VG: %d [%s]",
+                               pvs_found,
+                               display_size(cmd, size_total),
+                               pvs_found - new_pvs_found,
+                               display_size(cmd, (size_total - size_new)),
+                               new_pvs_found, display_size(cmd, size_new));
 
        unlock_vg(cmd, VG_GLOBAL);
 
index fbd0c27453825d0e11a763b0d6cd1eaa324a4071..1c8e39d1b99172da8bc8081f6f47d86826180f54 100644 (file)
@@ -51,7 +51,6 @@ static int _segs_single(struct cmd_context *cmd __attribute__((unused)),
 
        return ECMD_PROCESSED;
 }
-
 static int _pvsegs_sub_single(struct cmd_context *cmd,
                              struct volume_group *vg,
                              struct pv_segment *pvseg, void *handle)
@@ -61,15 +60,13 @@ static int _pvsegs_sub_single(struct cmd_context *cmd,
 
        struct volume_group _free_vg = {
                .cmd = cmd,
-               .name = (char *)"",
+               .name = "",
+               .vgmem = NULL,
        };
 
-        if (!(_free_vg.vgmem = dm_pool_create("_free_vg", 10240)))
-               return ECMD_FAILED;
-
        struct logical_volume _free_logical_volume = {
                .vg = vg ?: &_free_vg,
-               .name = (char *) "",
+               .name = "",
                .snapshot = NULL,
                .status = VISIBLE_LV,
                .major = -1,
@@ -109,8 +106,8 @@ static int _pvsegs_sub_single(struct cmd_context *cmd,
                ret = ECMD_FAILED;
                 goto_out;
        }
+
  out:
-       free_vg(&_free_vg);
        return ret;
 }
 
@@ -145,7 +142,7 @@ static int _pvs_single(struct cmd_context *cmd, struct volume_group *vg,
                vg = vg_read(cmd, vg_name, (char *)&pv->vgid, 0);
                if (vg_read_error(vg)) {
                        log_error("Skipping volume group %s", vg_name);
-                       free_vg(vg);
+                       release_vg(vg);
                        return ECMD_FAILED;
                }
 
@@ -185,7 +182,7 @@ out:
                unlock_vg(cmd, vg_name);
 
        if (!old_vg)
-               free_vg(vg);
+               release_vg(vg);
 
        return ret;
 }
@@ -318,6 +315,9 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
                                                  "report/pvsegs_cols_verbose",
                                                  DEFAULT_PVSEGS_COLS_VERB);
                break;
+       default:
+               log_error(INTERNAL_ERROR "Unknown report type.");
+               return ECMD_FAILED;
        }
 
        /* If -o supplied use it, else use default for report_type */
index f76aacda3174e976c351caec0267267e82bc7a22..3fe1c14c2325004eb6d9e240ba93c89de87c80c4 100644 (file)
  */
 
 #include "tools.h"
-#include "lv_alloc.h"
-#include "xlate.h"
-
 #include <sys/stat.h>
-#include <sys/wait.h>
 
 const char *command_name(struct cmd_context *cmd)
 {
@@ -28,7 +24,7 @@ const char *command_name(struct cmd_context *cmd)
 /*
  * Strip dev_dir if present
  */
-char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
+const char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
                   unsigned *dev_dir_found)
 {
        const char *dmdir = dm_dir();
@@ -54,7 +50,7 @@ char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
                    *layer) {
                        log_error("skip_dev_dir: Couldn't split up device name %s",
                                  vg_name);
-                       return (char *) vg_name;
+                       return vg_name;
                }
                vglv_sz = strlen(vgname) + strlen(lvname) + 2;
                if (!(vglv = dm_pool_alloc(cmd->mem, vglv_sz)) ||
@@ -62,7 +58,7 @@ char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
                                 *lvname ? "/" : "",
                                 lvname) < 0) {
                        log_error("vg/lv string alloc failed");
-                       return (char *) vg_name;
+                       return vg_name;
                }
                return vglv;
        }
@@ -76,7 +72,7 @@ char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
        } else if (dev_dir_found)
                *dev_dir_found = 0;
 
-       return (char *) vg_name;
+       return vg_name;
 }
 
 /*
@@ -119,10 +115,20 @@ int process_each_lv_in_vg(struct cmd_context *cmd,
                process_all = 1;
        }
 
+       /*
+        * FIXME: In case of remove it goes through deleted entries,
+        * but it works since entries are allocated from vg mem pool.
+        */
        dm_list_iterate_items(lvl, &vg->lvs) {
                if (lvl->lv->status & SNAPSHOT)
                        continue;
 
+               /* Skip availability change for non-virt snaps when processing all LVs */
+               /* FIXME: pass process_all to process_single_lv() */
+               if (process_all && arg_count(cmd, activate_ARG) &&
+                   lv_is_cow(lvl->lv) && !lv_is_virtual_origin(origin_from_cow(lvl->lv)))
+                       continue;
+
                if (lv_is_virtual_origin(lvl->lv) && !arg_count(cmd, all_ARG))
                        continue;
 
@@ -169,11 +175,17 @@ int process_each_lv_in_vg(struct cmd_context *cmd,
                }
                if (ret > ret_max)
                        ret_max = ret;
-               if (sigint_caught())
+               if (sigint_caught()) {
+                       stack;
                        return ret_max;
+               }
        }
 
        if (lvargs_supplied && lvargs_matched != dm_list_size(arg_lvnames)) {
+               /*
+                * FIXME: lvm supports removal of LV with all its dependencies
+                * this leads to miscalculation that depends on the order of args.
+                */
                log_error("One or more specified logical volume(s) not found.");
                if (ret_max < ECMD_FAILED)
                        ret_max = ECMD_FAILED;
@@ -253,8 +265,10 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
                                while (*lv_name == '/')
                                        lv_name++;
                                if (!(vgname = extract_vgname(cmd, vgname))) {
-                                       if (ret_max < ECMD_FAILED)
+                                       if (ret_max < ECMD_FAILED) {
+                                               stack;
                                                ret_max = ECMD_FAILED;
+                                       }
                                        continue;
                                }
                        } else if (!dev_dir_found &&
@@ -295,6 +309,8 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
 
        if (!argc || !dm_list_empty(&tags)) {
                log_verbose("Finding all logical volumes");
+               if (!lvmetad_vg_list_to_lvmcache(cmd))
+                       stack;
                if (!(vgnames = get_vgnames(cmd, 0)) || dm_list_empty(vgnames)) {
                        log_error("No volume groups found");
                        return ret_max;
@@ -347,8 +363,12 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
                        ret = process_each_lv_in_vg(cmd, cvl_vg->vg, &lvnames,
                                                    tags_arg, &failed_lvnames,
                                                    handle, process_single_lv);
-                       if (ret != ECMD_PROCESSED ||
-                           dm_list_empty(&failed_lvnames))
+                       if (ret != ECMD_PROCESSED) {
+                               stack;
+                               break;
+                       }
+
+                       if (dm_list_empty(&failed_lvnames))
                                break;
 
                        /* Try again with failed LVs in this VG */
@@ -357,6 +377,7 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
 
                        free_cmd_vgs(&cmd_vgs);
                        if (!cmd_vg_read(cmd, &cmd_vgs)) {
+                               stack;
                                ret = ECMD_FAILED; /* break */
                                break;
                        }
@@ -366,8 +387,10 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
 
                free_cmd_vgs(&cmd_vgs);
                /* FIXME: logic for breaking command is not consistent */
-               if (sigint_caught())
+               if (sigint_caught()) {
+                       stack;
                        return ECMD_FAILED;
+               }
        }
 
        return ret_max;
@@ -392,7 +415,7 @@ int process_each_segment_in_pv(struct cmd_context *cmd,
 
                vg = vg_read(cmd, vg_name, NULL, 0);
                if (vg_read_error(vg)) {
-                       free_vg(vg);
+                       release_vg(vg);
                        log_error("Skipping volume group %s", vg_name);
                        return ECMD_FAILED;
                }
@@ -404,7 +427,7 @@ int process_each_segment_in_pv(struct cmd_context *cmd,
                if (!(pvl = find_pv_in_vg(vg, pv_dev_name(pv)))) {
                         log_error("Unable to find %s in volume group %s",
                                   pv_dev_name(pv), vg_name);
-                        unlock_and_free_vg(cmd, vg, vg_name);
+                        unlock_and_release_vg(cmd, vg, vg_name);
                         return ECMD_FAILED;
                }
 
@@ -427,7 +450,7 @@ int process_each_segment_in_pv(struct cmd_context *cmd,
        if (vg_name)
                unlock_vg(cmd, vg_name);
        if (!old_vg)
-               free_vg(vg);
+               release_vg(vg);
 
        return ret_max;
 }
@@ -472,7 +495,7 @@ static int _process_one_vg(struct cmd_context *cmd, const char *vg_name,
        for (;;) {
                /* FIXME: consistent handling of command break */
                if (sigint_caught()) {
-                        ret = ECMD_FAILED;
+                       ret = ECMD_FAILED;
                        break;
                }
                if (!cmd_vg_read(cmd, &cmd_vgs))
@@ -564,13 +587,15 @@ int process_each_vg(struct cmd_context *cmd, int argc, char **argv,
 
        if (!argc || !dm_list_empty(&tags)) {
                log_verbose("Finding all volume groups");
+               if (!lvmetad_vg_list_to_lvmcache(cmd))
+                       stack;
                if (!(vgids = get_vgids(cmd, 0)) || dm_list_empty(vgids)) {
                        log_error("No volume groups found");
                        return ret_max;
                }
                dm_list_iterate_items(sl, vgids) {
                        vgid = sl->str;
-                       if (!(vgid) || !(vg_name = vgname_from_vgid(cmd->mem, vgid)))
+                       if (!(vgid) || !(vg_name = lvmcache_vgname_from_vgid(cmd->mem, vgid)))
                                continue;
                        ret_max = _process_one_vg(cmd, vg_name, vgid, &tags,
                                                  &arg_vgnames,
@@ -640,15 +665,17 @@ static int _process_all_devs(struct cmd_context *cmd, void *handle,
        }
 
        while ((dev = dev_iter_get(iter))) {
-               if (!(pv = pv_read(cmd, dev_name(dev), NULL, NULL, 0, 0))) {
+               if (!(pv = pv_read(cmd, dev_name(dev), 0, 0))) {
                        memset(&pv_dummy, 0, sizeof(pv_dummy));
                        dm_list_init(&pv_dummy.tags);
                        dm_list_init(&pv_dummy.segments);
                        pv_dummy.dev = dev;
-                       pv_dummy.fmt = NULL;
                        pv = &pv_dummy;
                }
                ret = process_single_pv(cmd, NULL, pv, handle);
+
+               free_pv_fid(pv);
+
                if (ret > ret_max)
                        ret_max = ret;
                if (sigint_caught())
@@ -682,7 +709,6 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
        struct str_list *sll;
        char *at_sign, *tagname;
        int scanned = 0;
-       struct dm_list mdas;
 
        dm_list_init(&tags);
 
@@ -694,7 +720,7 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
        if (argc) {
                log_verbose("Using physical volume(s) on command line");
                for (; opt < argc; opt++) {
-                       unescape_colons_and_at_signs(argv[opt], NULL, &at_sign);
+                       dm_unescape_colons_and_at_signs(argv[opt], NULL, &at_sign);
                        if (at_sign && (at_sign == argv[opt])) {
                                tagname = at_sign + 1;
 
@@ -724,10 +750,8 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
                                }
                                pv = pvl->pv;
                        } else {
-
-                               dm_list_init(&mdas);
-                               if (!(pv = pv_read(cmd, argv[opt], &mdas,
-                                                  NULL, 1, scan_label_only))) {
+                               if (!(pv = pv_read(cmd, argv[opt],
+                                                  1, scan_label_only))) {
                                        log_error("Failed to read physical "
                                                  "volume \"%s\"", argv[opt]);
                                        ret_max = ECMD_FAILED;
@@ -742,7 +766,7 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
                                 * PV on the system.
                                 */
                                if (!scanned && is_orphan(pv) &&
-                                   !dm_list_size(&mdas)) {
+                                   !dm_list_size(&pv->fid->metadata_areas_in_use)) {
                                        if (!scan_label_only &&
                                            !scan_vgs_for_pvs(cmd, 1)) {
                                                stack;
@@ -750,8 +774,9 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
                                                continue;
                                        }
                                        scanned = 1;
+                                       free_pv_fid(pv);
                                        if (!(pv = pv_read(cmd, argv[opt],
-                                                          NULL, NULL, 1,
+                                                          1,
                                                           scan_label_only))) {
                                                log_error("Failed to read "
                                                          "physical volume "
@@ -763,6 +788,14 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
                        }
 
                        ret = process_single_pv(cmd, vg, pv, handle);
+
+                       /*
+                        * Free PV only if we called pv_read before,
+                        * otherwise the PV structure is part of the VG.
+                        */
+                       if (!vg)
+                               free_pv_fid(pv);
+
                        if (ret > ret_max)
                                ret_max = ret;
                        if (sigint_caught())
@@ -774,7 +807,7 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
                                vg = vg_read(cmd, sll->str, NULL, flags);
                                if (vg_read_error(vg)) {
                                        ret_max = ECMD_FAILED;
-                                       free_vg(vg);
+                                       release_vg(vg);
                                        stack;
                                        continue;
                                }
@@ -783,7 +816,7 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
                                                            handle,
                                                            process_single_pv);
 
-                               unlock_and_free_vg(cmd, vg, sll->str);
+                               unlock_and_release_vg(cmd, vg, sll->str);
 
                                if (ret > ret_max)
                                        ret_max = ret;
@@ -810,12 +843,14 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
                } else {
                        log_verbose("Scanning for physical volume names");
 
+                       lvmcache_seed_infos_from_lvmetad(cmd);
                        if (!(pvslist = get_pvs(cmd)))
                                goto bad;
 
                        dm_list_iterate_items(pvl, pvslist) {
                                ret = process_single_pv(cmd, NULL, pvl->pv,
                                                     handle);
+                               free_pv_fid(pvl->pv);
                                if (ret > ret_max)
                                        ret_max = ret;
                                if (sigint_caught())
@@ -898,7 +933,7 @@ const char *extract_vgname(struct cmd_context *cmd, const char *lv_name)
  */
 char *default_vgname(struct cmd_context *cmd)
 {
-       char *vg_path;
+       const char *vg_path;
 
        /* Take default VG from environment? */
        vg_path = getenv("LVM_VG_NAME");
@@ -959,10 +994,11 @@ static int xstrtouint32(const char *s, char **p, int base, uint32_t *result)
 
        errno = 0;
        ul = strtoul(s, p, base);
-       if (errno || *p == s || (uint32_t) ul != ul)
-               return -1;
+       if (errno || *p == s || ul > UINT32_MAX)
+               return 0;
        *result = ul;
-       return 0;
+
+       return 1;
 }
 
 static int _parse_pes(struct dm_pool *mem, char *c, struct dm_list *pe_ranges,
@@ -994,7 +1030,7 @@ static int _parse_pes(struct dm_pool *mem, char *c, struct dm_list *pe_ranges,
 
                /* Start extent given? */
                if (isdigit(*c)) {
-                       if (xstrtouint32(c, &endptr, 10, &start))
+                       if (!xstrtouint32(c, &endptr, 10, &start))
                                goto error;
                        c = endptr;
                        /* Just one number given? */
@@ -1005,7 +1041,7 @@ static int _parse_pes(struct dm_pool *mem, char *c, struct dm_list *pe_ranges,
                if (*c == '-') {
                        c++;
                        if (isdigit(*c)) {
-                               if (xstrtouint32(c, &endptr, 10, &end))
+                               if (!xstrtouint32(c, &endptr, 10, &end))
                                        goto error;
                                c = endptr;
                        }
@@ -1107,7 +1143,7 @@ struct dm_list *create_pv_list(struct dm_pool *mem, struct volume_group *vg, int
        dm_list_init(&arg_pvnames);
 
        for (i = 0; i < argc; i++) {
-               unescape_colons_and_at_signs(argv[i], &colon, &at_sign);
+               dm_unescape_colons_and_at_signs(argv[i], &colon, &at_sign);
 
                if (at_sign && (at_sign == argv[i])) {
                        tagname = at_sign + 1;
@@ -1212,7 +1248,7 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd,
                                        vp_def->max_lv);
        vp_new->max_pv = arg_uint_value(cmd, maxphysicalvolumes_ARG,
                                        vp_def->max_pv);
-       vp_new->alloc = arg_uint_value(cmd, alloc_ARG, vp_def->alloc);
+       vp_new->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, vp_def->alloc);
 
        /* Units of 512-byte sectors */
        vp_new->extent_size =
@@ -1226,17 +1262,23 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd,
                /* Default depends on current locking type */
                vp_new->clustered = locking_is_clustered();
 
-       if (arg_sign_value(cmd, physicalextentsize_ARG, 0) == SIGN_MINUS) {
+       if (arg_sign_value(cmd, physicalextentsize_ARG, SIGN_NONE) == SIGN_MINUS) {
                log_error("Physical extent size may not be negative");
                return 1;
        }
 
-       if (arg_sign_value(cmd, maxlogicalvolumes_ARG, 0) == SIGN_MINUS) {
+       if (arg_uint64_value(cmd, physicalextentsize_ARG, 0) > MAX_EXTENT_SIZE) {
+               log_error("Physical extent size cannot be larger than %s",
+                                 display_size(cmd, (uint64_t) MAX_EXTENT_SIZE));
+               return 1;
+       }
+
+       if (arg_sign_value(cmd, maxlogicalvolumes_ARG, SIGN_NONE) == SIGN_MINUS) {
                log_error("Max Logical Volumes may not be negative");
                return 1;
        }
 
-       if (arg_sign_value(cmd, maxphysicalvolumes_ARG, 0) == SIGN_MINUS) {
+       if (arg_sign_value(cmd, maxphysicalvolumes_ARG, SIGN_NONE) == SIGN_MINUS) {
                log_error("Max Physical Volumes may not be negative");
                return 1;
        }
@@ -1295,10 +1337,17 @@ int vg_refresh_visible(struct cmd_context *cmd, struct volume_group *vg)
        struct lv_list *lvl;
        int r = 1;
 
-       dm_list_iterate_items(lvl, &vg->lvs)
+       sigint_allow();
+       dm_list_iterate_items(lvl, &vg->lvs) {
+               if (sigint_caught())
+                       return_0;
+
                if (lv_is_visible(lvl->lv))
                        if (!lv_refresh(cmd, lvl->lv))
                                r = 0;
+       }
+
+       sigint_restore();
 
        return r;
 }
@@ -1343,7 +1392,7 @@ int pvcreate_params_validate(struct cmd_context *cmd,
        }
 
        pp->yes = arg_count(cmd, yes_ARG);
-       pp->force = arg_count(cmd, force_ARG);
+       pp->force = (force_t) arg_count(cmd, force_ARG);
 
        if (arg_int_value(cmd, labelsector_ARG, 0) >= LABEL_SCAN_SECTORS) {
                log_error("labelsector must be less than %lu",
@@ -1391,13 +1440,13 @@ int pvcreate_params_validate(struct cmd_context *cmd,
        if (arg_count(cmd, zero_ARG))
                pp->zero = strcmp(arg_str_value(cmd, zero_ARG, "y"), "n");
 
-       if (arg_sign_value(cmd, dataalignment_ARG, 0) == SIGN_MINUS) {
+       if (arg_sign_value(cmd, dataalignment_ARG, SIGN_NONE) == SIGN_MINUS) {
                log_error("Physical volume data alignment may not be negative");
                return 0;
        }
        pp->data_alignment = arg_uint64_value(cmd, dataalignment_ARG, UINT64_C(0));
 
-       if (pp->data_alignment > ULONG_MAX) {
+       if (pp->data_alignment > UINT32_MAX) {
                log_error("Physical volume data alignment is too big.");
                return 0;
        }
@@ -1410,13 +1459,13 @@ int pvcreate_params_validate(struct cmd_context *cmd,
                pp->data_alignment = 0;
        }
 
-       if (arg_sign_value(cmd, dataalignmentoffset_ARG, 0) == SIGN_MINUS) {
+       if (arg_sign_value(cmd, dataalignmentoffset_ARG, SIGN_NONE) == SIGN_MINUS) {
                log_error("Physical volume data alignment offset may not be negative");
                return 0;
        }
        pp->data_alignment_offset = arg_uint64_value(cmd, dataalignmentoffset_ARG, UINT64_C(0));
 
-       if (pp->data_alignment_offset > ULONG_MAX) {
+       if (pp->data_alignment_offset > UINT32_MAX) {
                log_error("Physical volume data alignment offset is too big.");
                return 0;
        }
@@ -1428,7 +1477,7 @@ int pvcreate_params_validate(struct cmd_context *cmd,
                pp->data_alignment_offset = 0;
        }
 
-       if (arg_sign_value(cmd, metadatasize_ARG, 0) == SIGN_MINUS) {
+       if (arg_sign_value(cmd, metadatasize_ARG, SIGN_NONE) == SIGN_MINUS) {
                log_error("Metadata size may not be negative");
                return 0;
        }
@@ -1449,7 +1498,6 @@ int pvcreate_params_validate(struct cmd_context *cmd,
 }
 
 int get_activation_monitoring_mode(struct cmd_context *cmd,
-                                  struct volume_group *vg,
                                   int *monitoring_mode)
 {
        *monitoring_mode = DEFAULT_DMEVENTD_MONITOR;
@@ -1470,16 +1518,6 @@ int get_activation_monitoring_mode(struct cmd_context *cmd,
                                        DEFAULT_DMEVENTD_MONITOR))
                *monitoring_mode = DMEVENTD_MONITOR_IGNORE;
 
-       if (vg && vg_is_clustered(vg) &&
-           *monitoring_mode == DMEVENTD_MONITOR_IGNORE) {
-               log_error("%s is incompatible with clustered Volume Group "
-                         "\"%s\": Skipping.",
-                         (arg_count(cmd, ignoremonitoring_ARG) ?
-                          "--ignoremonitoring" : "activation/monitoring=0"),
-                         vg->name);
-               return 0;
-       }
-       
        return 1;
 }
 
@@ -1490,13 +1528,13 @@ static int _validate_stripe_params(struct cmd_context *cmd, uint32_t *stripes,
                                   uint32_t *stripe_size)
 {
        if (*stripes == 1 && *stripe_size) {
-               log_print("Ignoring stripesize argument with single stripe");
+               log_print_unless_silent("Ignoring stripesize argument with single stripe");
                *stripe_size = 0;
        }
 
        if (*stripes > 1 && !*stripe_size) {
                *stripe_size = find_config_tree_int(cmd, "metadata/stripesize", DEFAULT_STRIPESIZE) * 2;
-               log_print("Using default stripesize %s",
+               log_print_unless_silent("Using default stripesize %s",
                          display_size(cmd, (uint64_t) *stripe_size));
        }
 
@@ -1525,16 +1563,16 @@ static int _validate_stripe_params(struct cmd_context *cmd, uint32_t *stripes,
 int get_stripe_params(struct cmd_context *cmd, uint32_t *stripes, uint32_t *stripe_size)
 {
        /* stripes_long_ARG takes precedence (for lvconvert) */
-        *stripes = arg_uint_value(cmd, arg_count(cmd, stripes_long_ARG) ? stripes_long_ARG : stripes_ARG, 1);
+       *stripes = arg_uint_value(cmd, arg_count(cmd, stripes_long_ARG) ? stripes_long_ARG : stripes_ARG, 1);
 
        *stripe_size = arg_uint_value(cmd, stripesize_ARG, 0);
        if (*stripe_size) {
-               if (arg_sign_value(cmd, stripesize_ARG, 0) == SIGN_MINUS) {
+               if (arg_sign_value(cmd, stripesize_ARG, SIGN_NONE) == SIGN_MINUS) {
                        log_error("Negative stripesize is invalid");
                        return 0;
                }
 
-               if(*stripe_size > STRIPE_SIZE_LIMIT * 2) {
+               if(arg_uint64_value(cmd, stripesize_ARG, 0) > STRIPE_SIZE_LIMIT * 2) {
                        log_error("Stripe size cannot be larger than %s",
                                  display_size(cmd, (uint64_t) STRIPE_SIZE_LIMIT));
                        return 0;
@@ -1544,3 +1582,51 @@ int get_stripe_params(struct cmd_context *cmd, uint32_t *stripes, uint32_t *stri
        return _validate_stripe_params(cmd, stripes, stripe_size);
 }
 
+/* FIXME move to lib */
+static int _pv_change_tag(struct physical_volume *pv, const char *tag, int addtag)
+{
+       if (addtag) {
+               if (!str_list_add(pv->fmt->cmd->mem, &pv->tags, tag)) {
+                       log_error("Failed to add tag %s to physical volume %s",
+                                 tag, pv_dev_name(pv));
+                       return 0;
+               }
+       } else
+               str_list_del(&pv->tags, tag);
+
+       return 1;
+}
+
+/* Set exactly one of VG, LV or PV */
+int change_tag(struct cmd_context *cmd, struct volume_group *vg,
+              struct logical_volume *lv, struct physical_volume *pv, int arg)
+{
+       const char *tag;
+       struct arg_value_group_list *current_group;
+
+       dm_list_iterate_items(current_group, &cmd->arg_value_groups) {
+               if (!grouped_arg_is_set(current_group->arg_values, arg))
+                       continue;
+
+               if (!(tag = grouped_arg_str_value(current_group->arg_values, arg, NULL))) {
+                       log_error("Failed to get tag");
+                       return 0;
+               }
+
+               if (vg && !vg_change_tag(vg, tag, arg == addtag_ARG))
+                       return_0;
+               else if (lv && !lv_change_tag(lv, tag, arg == addtag_ARG))
+                       return_0;
+               else if (pv && !_pv_change_tag(pv, tag, arg == addtag_ARG))
+                       return_0;
+       }
+
+       return 1;
+}
+
+/* Return percents of extents and avoid overflow, with optional roundup */
+uint32_t percent_of_extents(uint32_t percents, uint32_t count, int roundup)
+{
+       return (uint32_t)(((uint64_t)percents * (uint64_t)count +
+                          ((roundup) ? 99 : 0)) / 100);
+}
index 71e516fb5c0b85725c32d89ee18effa3d649550f..b3b0a7c1665efe8dd6d03606380f303723b1d72d 100644 (file)
@@ -84,8 +84,8 @@ int process_each_lv_in_vg(struct cmd_context *cmd,
 
 char *default_vgname(struct cmd_context *cmd);
 const char *extract_vgname(struct cmd_context *cmd, const char *lv_name);
-char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
-                  unsigned *dev_dir_found);
+const char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
+                        unsigned *dev_dir_found);
 
 /*
  * Builds a list of pv's from the names in argv.  Used in
@@ -110,9 +110,11 @@ int pvcreate_params_validate(struct cmd_context *cmd,
                             struct pvcreate_params *pp);
 
 int get_activation_monitoring_mode(struct cmd_context *cmd,
-                                  struct volume_group *vg,
                                   int *monitoring_mode);
 int get_stripe_params(struct cmd_context *cmd, uint32_t *stripes,
                      uint32_t *stripe_size);
 
+int change_tag(struct cmd_context *cmd, struct volume_group *vg,
+              struct logical_volume *lv, struct physical_volume *pv, int arg);
+
 #endif
index cfbceeb4733836a3df11fa72dad43728ea0f6e93..a3ad9fdbaf0364e7dc143f106aba73e9cd5e475d 100644 (file)
@@ -28,6 +28,7 @@
 #include "activate.h"
 #include "archiver.h"
 #include "lvmcache.h"
+#include "lvmetad.h"
 #include "config.h"
 #include "defaults.h"
 #include "dev-cache.h"
@@ -87,14 +88,6 @@ typedef enum {
        PERCENT_ORIGIN
 } percent_type_t;
 
-enum {
-       CHANGE_AY = 0,
-       CHANGE_AN = 1,
-       CHANGE_AE = 2,
-       CHANGE_ALY = 3,
-       CHANGE_ALN = 4
-};
-
 #define ARG_COUNTABLE 0x00000001       /* E.g. -vvvv */
 #define ARG_GROUPABLE 0x00000002       /* E.g. --addtag */
 
@@ -145,7 +138,8 @@ void usage(const char *name);
 
 /* the argument verify/normalise functions */
 int yes_no_arg(struct cmd_context *cmd, struct arg_values *av);
-int yes_no_excl_arg(struct cmd_context *cmd, struct arg_values *av);
+int activation_arg(struct cmd_context *cmd, struct arg_values *av);
+int discards_arg(struct cmd_context *cmd, struct arg_values *av);
 int size_kb_arg(struct cmd_context *cmd, struct arg_values *av);
 int size_mb_arg(struct cmd_context *cmd, struct arg_values *av);
 int int_arg(struct cmd_context *cmd, struct arg_values *av);
@@ -162,6 +156,8 @@ int segtype_arg(struct cmd_context *cmd, struct arg_values *av);
 int alloc_arg(struct cmd_context *cmd, struct arg_values *av);
 int readahead_arg(struct cmd_context *cmd, struct arg_values *av);
 int metadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
+int major_minor_valid(const struct cmd_context * cmd, const struct format_type *fmt,
+                     int32_t major, int32_t minor);
 
 /* we use the enums to access the switches */
 unsigned arg_count(const struct cmd_context *cmd, int a);
@@ -169,6 +165,7 @@ unsigned arg_is_set(const struct cmd_context *cmd, int a);
 const char *arg_value(struct cmd_context *cmd, int a);
 const char *arg_str_value(struct cmd_context *cmd, int a, const char *def);
 int32_t arg_int_value(struct cmd_context *cmd, int a, const int32_t def); 
+int32_t first_grouped_arg_int_value(struct cmd_context *cmd, int a, const int32_t def); 
 uint32_t arg_uint_value(struct cmd_context *cmd, int a, const uint32_t def);
 int64_t arg_int64_value(struct cmd_context *cmd, int a, const int64_t def);
 uint64_t arg_uint64_value(struct cmd_context *cmd, int a, const uint64_t def);
@@ -180,10 +177,18 @@ int arg_count_increment(struct cmd_context *cmd, int a);
 unsigned grouped_arg_count(const struct arg_values *av, int a);
 unsigned grouped_arg_is_set(const struct arg_values *av, int a);
 const char *grouped_arg_str_value(const struct arg_values *av, int a, const char *def);
+int32_t grouped_arg_int_value(const struct arg_values *av, int a, const int32_t def); 
 
 const char *command_name(struct cmd_context *cmd);
 
 int pvmove_poll(struct cmd_context *cmd, const char *pv, unsigned background);
 int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv, unsigned background);
 
+int mirror_remove_missing(struct cmd_context *cmd,
+                         struct logical_volume *lv, int force);
+
+uint32_t percent_of_extents(uint32_t percents, uint32_t count, int roundup);
+
+int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
+                      activation_change_t activate);
 #endif
index 2be3949362a4a2c3d1622857ebc0bc710483e419..32948d877116caec6995e827940697303899e1ef 100644 (file)
@@ -28,7 +28,7 @@ static char *_expand_filename(const char *template, const char *vg_name,
                return NULL;
        }
 
-       if (snprintf(filename, PATH_MAX, template, vg_name) < 0) {
+       if (dm_snprintf(filename, PATH_MAX, template, vg_name) < 0) {
                log_error("Error processing filename template %s",
                           template);
                dm_free(filename);      
@@ -81,7 +81,7 @@ static int vg_backup_single(struct cmd_context *cmd, const char *vg_name,
                }
        }
 
-       log_print("Volume group \"%s\" successfully backed up.", vg_name);
+       log_print_unless_silent("Volume group \"%s\" successfully backed up.", vg_name);
        return ECMD_PROCESSED;
 }
 
index dc0158f8e47b6f1f57035892a8f06992f94e45d8..d62df99f7675e34089c295603d9e563ae552eddf 100644 (file)
@@ -17,7 +17,7 @@
 
 int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv)
 {
-       char *vg_name = NULL;
+       const char *vg_name = NULL;
 
        if (argc == 1) {
                vg_name = skip_dev_dir(cmd, argv[0], NULL);
@@ -45,6 +45,8 @@ int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv)
                return ECMD_PROCESSED;
        }
 
+       lvmcache_seed_infos_from_lvmetad(cmd);
+
        if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
                log_error("Unable to lock volume group %s", vg_name);
                return ECMD_FAILED;
@@ -68,7 +70,7 @@ int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv)
                return ECMD_FAILED;
        }
 
-       log_print("Restored volume group %s", vg_name);
+       log_print_unless_silent("Restored volume group %s", vg_name);
 
        unlock_vg(cmd, VG_ORPHANS);
        unlock_vg(cmd, vg_name);
index bf7ebd8f344881e8d99c0bf0b7000bce0274d39c..a897a8534c5143848c7a3f802ec9d4cd9751e594 100644 (file)
@@ -24,21 +24,19 @@ static int _monitor_lvs_in_vg(struct cmd_context *cmd,
        struct lv_list *lvl;
        struct logical_volume *lv;
        struct lvinfo info;
-       int lv_active;
        int r = 1;
 
        dm_list_iterate_items(lvl, &vg->lvs) {
                lv = lvl->lv;
 
-               if (!lv_info(cmd, lv, 0, &info, 0, 0))
-                       lv_active = 0;
-               else
-                       lv_active = info.exists;
-
+               if (!lv_info(cmd, lv, lv_is_thin_pool(lv) ? 1 : 0,
+                            &info, 0, 0) ||
+                   !info.exists)
+                       continue;
                /*
                 * FIXME: Need to consider all cases... PVMOVE, etc
                 */
-               if ((lv->status & PVMOVE) || !lv_active)
+               if (lv->status & PVMOVE)
                        continue;
 
                if (!monitor_dev_for_events(cmd, lv, 0, reg)) {
@@ -83,19 +81,27 @@ static int _poll_lvs_in_vg(struct cmd_context *cmd,
        return count;
 }
 
-static int _activate_lvs_in_vg(struct cmd_context *cmd,
-                              struct volume_group *vg, int activate)
+static int _activate_lvs_in_vg(struct cmd_context *cmd, struct volume_group *vg,
+                              activation_change_t activate)
 {
        struct lv_list *lvl;
        struct logical_volume *lv;
        int count = 0, expected_count = 0;
 
+       sigint_allow();
        dm_list_iterate_items(lvl, &vg->lvs) {
+               if (sigint_caught())
+                       return_0;
+
                lv = lvl->lv;
 
                if (!lv_is_visible(lv))
                        continue;
 
+               /* If LV is sparse, activate origin instead */
+               if (lv_is_cow(lv) && lv_is_virtual_origin(origin_from_cow(lv)))
+                       lv = origin_from_cow(lv);
+
                /* Only request activation of snapshot origin devices */
                if ((lv->status & SNAPSHOT) || lv_is_cow(lv))
                        continue;
@@ -115,6 +121,19 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd,
                    ((lv->status & PVMOVE) ))
                        continue;
 
+               /*
+                * If the LV is active exclusive remotely,
+                * then ignore it here
+                */
+               if (lv_is_active_exclusive_remotely(lv)) {
+                       log_verbose("%s/%s is exclusively active on"
+                                   " a remote node", vg->name, lv->name);
+                       continue;
+               }
+
+               if (activate == CHANGE_AAY && !lv_passes_auto_activation_filter(cmd, lv))
+                       continue;
+
                expected_count++;
 
                if (activate == CHANGE_AN) {
@@ -127,12 +146,15 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd,
                                stack;
                                continue;
                        }
-               } else if (lv_is_origin(lv) || (activate == CHANGE_AE)) {
+               } else if ((activate == CHANGE_AE) ||
+                          lv_is_origin(lv) ||
+                          lv_is_thin_type(lv)) {
+                       /* FIXME: duplicated test code with lvchange */
                        if (!activate_lv_excl(cmd, lv)) {
                                stack;
                                continue;
                        }
-               } else if (activate == CHANGE_ALY) {
+               } else if (activate == CHANGE_AAY || activate == CHANGE_ALY) {
                        if (!activate_lv_local(cmd, lv)) {
                                stack;
                                continue;
@@ -150,6 +172,8 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd,
                count++;
        }
 
+       sigint_restore();
+
        if (expected_count)
                log_verbose("%s %d logical volumes in volume group %s",
                            (activate == CHANGE_AN || activate == CHANGE_ALN)?
@@ -167,9 +191,9 @@ static int _vgchange_monitoring(struct cmd_context *cmd, struct volume_group *vg
            dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) {
                if (!_monitor_lvs_in_vg(cmd, vg, dmeventd_monitor_mode(), &monitored))
                        r = 0;
-               log_print("%d logical volume(s) in volume group "
-                           "\"%s\" %smonitored",
-                           monitored, vg->name, (dmeventd_monitor_mode()) ? "" : "un");
+               log_print_unless_silent("%d logical volume(s) in volume group "
+                                       "\"%s\" %smonitored",
+                                       monitored, vg->name, (dmeventd_monitor_mode()) ? "" : "un");
        }
 
        return r;
@@ -182,43 +206,40 @@ static int _vgchange_background_polling(struct cmd_context *cmd, struct volume_g
        if (lvs_in_vg_activated(vg) && background_polling()) {
                polled = _poll_lvs_in_vg(cmd, vg);
                if (polled)
-                       log_print("Background polling started for %d logical volume(s) "
-                                 "in volume group \"%s\"",
-                                 polled, vg->name);
+                       log_print_unless_silent("Background polling started for %d logical volume(s) "
+                                               "in volume group \"%s\"",
+                                               polled, vg->name);
        }
 
        return 1;
 }
 
-static int _vgchange_available(struct cmd_context *cmd, struct volume_group *vg)
+int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
+                     activation_change_t activate)
 {
-       int lv_open, active, monitored = 0;
-       int available, r = 1;
-       int activate = 1;
+       int lv_open, active, monitored = 0, r = 1, do_activate = 1;
+
+       if ((activate == CHANGE_AN) || (activate == CHANGE_ALN))
+               do_activate = 0;
 
        /*
         * Safe, since we never write out new metadata here. Required for
         * partial activation to work.
         */
-       cmd->handles_missing_pvs = 1;
-
-       available = arg_uint_value(cmd, available_ARG, 0);
-
-       if ((available == CHANGE_AN) || (available == CHANGE_ALN))
-               activate = 0;
+        cmd->handles_missing_pvs = 1;
 
        /* FIXME: Force argument to deactivate them? */
-       if (!activate && (lv_open = lvs_in_vg_opened(vg))) {
+       if (!do_activate && (lv_open = lvs_in_vg_opened(vg))) {
                log_error("Can't deactivate volume group \"%s\" with %d open "
                          "logical volume(s)", vg->name, lv_open);
                return 0;
        }
 
        /* FIXME Move into library where clvmd can use it */
-       if (activate)
+       if (do_activate)
                check_current_backup(vg);
 
-       if (activate && (active = lvs_in_vg_activated(vg))) {
+       if (do_activate && (active = lvs_in_vg_activated(vg))) {
                log_verbose("%d logical volume(s) in volume group \"%s\" "
                            "already active", active, vg->name);
                if (dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) {
@@ -231,13 +252,13 @@ static int _vgchange_available(struct cmd_context *cmd, struct volume_group *vg)
                }
        }
 
-       if (!_activate_lvs_in_vg(cmd, vg, available))
+       if (!_activate_lvs_in_vg(cmd, vg, activate))
                r = 0;
 
        /* Print message only if there was not found a missing VG */
        if (!vg->cmd_missing_vgs)
-               log_print("%d logical volume(s) in volume group \"%s\" now active",
-                         lvs_in_vg_activated(vg), vg->name);
+               log_print_unless_silent("%d logical volume(s) in volume group \"%s\" now active",
+                                       lvs_in_vg_activated(vg), vg->name);
        return r;
 }
 
@@ -257,7 +278,7 @@ static int _vgchange_alloc(struct cmd_context *cmd, struct volume_group *vg)
 {
        alloc_policy_t alloc;
 
-       alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_NORMAL);
+       alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, ALLOC_NORMAL);
 
        /* FIXME: make consistent with vg_set_alloc_policy() */
        if (alloc == vg->alloc) {
@@ -346,6 +367,12 @@ static int _vgchange_pesize(struct cmd_context *cmd, struct volume_group *vg)
 {
        uint32_t extent_size;
 
+       if (arg_uint64_value(cmd, physicalextentsize_ARG, 0) > MAX_EXTENT_SIZE) {
+               log_error("Physical extent size cannot be larger than %s",
+                                 display_size(cmd, (uint64_t) MAX_EXTENT_SIZE));
+               return 1;
+       }
+
        extent_size = arg_uint_value(cmd, physicalextentsize_ARG, 0);
        /* FIXME: remove check - redundant with vg_change_pesize */
        if (extent_size == vg->extent_size) {
@@ -360,37 +387,14 @@ static int _vgchange_pesize(struct cmd_context *cmd, struct volume_group *vg)
        return 1;
 }
 
-static int _vgchange_tag(struct cmd_context *cmd, struct volume_group *vg,
-                        int arg)
-{
-       const char *tag;
-       struct arg_value_group_list *current_group;
-
-       dm_list_iterate_items(current_group, &cmd->arg_value_groups) {
-               if (!grouped_arg_is_set(current_group->arg_values, arg))
-                       continue;
-
-               if (!(tag = grouped_arg_str_value(current_group->arg_values, arg, NULL))) {
-                       log_error("Failed to get tag");
-                       return 0;
-               }
-
-               if (!vg_change_tag(vg, tag, arg == addtag_ARG))
-                       return_0;
-
-       }
-
-       return 1;
-}
-
 static int _vgchange_addtag(struct cmd_context *cmd, struct volume_group *vg)
 {
-       return _vgchange_tag(cmd, vg, addtag_ARG);
+       return change_tag(cmd, vg, NULL, NULL, addtag_ARG);
 }
 
 static int _vgchange_deltag(struct cmd_context *cmd, struct volume_group *vg)
 {
-       return _vgchange_tag(cmd, vg, deltag_ARG);
+       return change_tag(cmd, vg, NULL, NULL, deltag_ARG);
 }
 
 static int _vgchange_uuid(struct cmd_context *cmd __attribute__((unused)),
@@ -441,7 +445,6 @@ static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
                           struct volume_group *vg,
                           void *handle __attribute__((unused)))
 {
-       int dmeventd_mode;
        int archived = 0;
        int i;
 
@@ -467,11 +470,6 @@ static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
                return ECMD_FAILED;
        }
 
-       if (!get_activation_monitoring_mode(cmd, vg, &dmeventd_mode))
-               return ECMD_FAILED;
-
-       init_dmeventd_monitor(dmeventd_mode);
-
        /*
         * FIXME: DEFAULT_BACKGROUND_POLLING should be "unspecified".
         * If --poll is explicitly provided use it; otherwise polling
@@ -507,11 +505,12 @@ static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
 
                backup(vg);
 
-               log_print("Volume group \"%s\" successfully changed", vg->name);
+               log_print_unless_silent("Volume group \"%s\" successfully changed", vg->name);
        }
 
-       if (arg_count(cmd, available_ARG)) {
-               if (!_vgchange_available(cmd, vg))
+       if (arg_count(cmd, activate_ARG)) {
+               if (!vgchange_activate(cmd, vg, (activation_change_t)
+                                      arg_uint_value(cmd, activate_ARG, CHANGE_AY)))
                        return ECMD_FAILED;
        }
 
@@ -521,7 +520,7 @@ static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
                        return ECMD_FAILED;
        }
 
-       if (!arg_count(cmd, available_ARG) &&
+       if (!arg_count(cmd, activate_ARG) &&
            !arg_count(cmd, refresh_ARG) &&
            arg_count(cmd, monitor_ARG)) {
                /* -ay* will have already done monitoring changes */
@@ -530,7 +529,7 @@ static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
        }
 
        if (!arg_count(cmd, refresh_ARG) &&
-           arg_count(cmd, poll_ARG))
+           background_polling())
                if (!_vgchange_background_polling(cmd, vg))
                        return ECMD_FAILED;
 
@@ -540,20 +539,22 @@ static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
 int vgchange(struct cmd_context *cmd, int argc, char **argv)
 {
        /* Update commands that can be combined */
-       int update = 
+       int update_partial_safe =
+               arg_count(cmd, deltag_ARG) ||
+               arg_count(cmd, addtag_ARG);
+       int update_partial_unsafe =
                arg_count(cmd, logicalvolume_ARG) ||
                arg_count(cmd, maxphysicalvolumes_ARG) ||
                arg_count(cmd, resizeable_ARG) ||
-               arg_count(cmd, deltag_ARG) ||
-               arg_count(cmd, addtag_ARG) ||
                arg_count(cmd, uuid_ARG) ||
                arg_count(cmd, physicalextentsize_ARG) ||
                arg_count(cmd, clustered_ARG) ||
                arg_count(cmd, alloc_ARG) ||
                arg_count(cmd, vgmetadatacopies_ARG);
+       int update = update_partial_safe || update_partial_unsafe;
 
        if (!update &&
-           !arg_count(cmd, available_ARG) &&
+           !arg_count(cmd, activate_ARG) &&
            !arg_count(cmd, monitor_ARG) &&
            !arg_count(cmd, poll_ARG) &&
            !arg_count(cmd, refresh_ARG)) {
@@ -564,7 +565,7 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
                return EINVALID_CMD_LINE;
        }
 
-       if (arg_count(cmd, available_ARG) && arg_count(cmd, refresh_ARG)) {
+       if (arg_count(cmd, activate_ARG) && arg_count(cmd, refresh_ARG)) {
                log_error("Only one of -a and --refresh permitted.");
                return EINVALID_CMD_LINE;
        }
@@ -575,9 +576,9 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
                return EINVALID_CMD_LINE;
        }
 
-       if (arg_count(cmd, available_ARG) &&
+       if (arg_count(cmd, activate_ARG) &&
            (arg_count(cmd, monitor_ARG) || arg_count(cmd, poll_ARG))) {
-               int activate = arg_uint_value(cmd, available_ARG, 0);
+               int activate = arg_uint_value(cmd, activate_ARG, 0);
                if (activate == CHANGE_AN || activate == CHANGE_ALN) {
                        log_error("Only -ay* allowed with --monitor or --poll.");
                        return EINVALID_CMD_LINE;
@@ -589,24 +590,34 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
                return EINVALID_CMD_LINE;
        }
 
-       if (arg_count(cmd, available_ARG) == 1
+       if (arg_count(cmd, activate_ARG) == 1
            && arg_count(cmd, autobackup_ARG)) {
                log_error("-A option not necessary with -a option");
                return EINVALID_CMD_LINE;
        }
 
        if (arg_count(cmd, maxphysicalvolumes_ARG) &&
-           arg_sign_value(cmd, maxphysicalvolumes_ARG, 0) == SIGN_MINUS) {
+           arg_sign_value(cmd, maxphysicalvolumes_ARG, SIGN_NONE) == SIGN_MINUS) {
                log_error("MaxPhysicalVolumes may not be negative");
                return EINVALID_CMD_LINE;
        }
 
        if (arg_count(cmd, physicalextentsize_ARG) &&
-           arg_sign_value(cmd, physicalextentsize_ARG, 0) == SIGN_MINUS) {
+           arg_sign_value(cmd, physicalextentsize_ARG, SIGN_NONE) == SIGN_MINUS) {
                log_error("Physical extent size may not be negative");
                return EINVALID_CMD_LINE;
        }
 
+       if (arg_count(cmd, sysinit_ARG) && lvmetad_active() &&
+           arg_uint_value(cmd, activate_ARG, 0) == CHANGE_AAY) {
+               log_warn("lvmetad is active while using --sysinit -a ay, "
+                        "skipping manual activation");
+               return ECMD_PROCESSED;
+       }
+
+       if (!update || !update_partial_unsafe)
+               cmd->handles_missing_pvs = 1;
+
        return process_each_vg(cmd, argc, argv, update ? READ_FOR_UPDATE : 0,
                               NULL, &vgchange_single);
 }
index acae0fcfa5948cfa514ead2af0ccbfe9f4470fff..2ba40952377de1a7c4fcea44e47a7b47042cc31b 100644 (file)
@@ -22,11 +22,9 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
        struct physical_volume *pv, *existing_pv;
        struct logical_volume *lv;
        struct lv_list *lvl;
-       uint64_t size = 0;
-       struct dm_list mdas;
        int pvmetadatacopies = 0;
        uint64_t pvmetadatasize = 0;
-       uint64_t pe_end = 0, pe_start = 0;
+       uint64_t pe_start = 0;
        struct pv_list *pvl;
        int change_made = 0;
        struct lvinfo info;
@@ -44,7 +42,7 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
        }
 
        if (cmd->fmt->features & FMT_MDAS) {
-               if (arg_sign_value(cmd, metadatasize_ARG, 0) == SIGN_MINUS) {
+               if (arg_sign_value(cmd, metadatasize_ARG, SIGN_NONE) == SIGN_MINUS) {
                        log_error("Metadata size may not be negative");
                        return EINVALID_CMD_LINE;
                }
@@ -119,15 +117,15 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
                existing_pv = pvl->pv;
 
                pe_start = pv_pe_start(existing_pv);
-               pe_end = pv_pe_count(existing_pv) * pv_pe_size(existing_pv)
-                   + pe_start - 1;
+               /* pe_end = pv_pe_count(existing_pv) * pv_pe_size(existing_pv) + pe_start - 1; */
 
-               dm_list_init(&mdas);
                if (!(pv = pv_create(cmd, pv_dev(existing_pv),
-                                    &existing_pv->id, size, 0, 0,
+                                    &existing_pv->id, 0, 0, 0,
                                     pe_start, pv_pe_count(existing_pv),
-                                    pv_pe_size(existing_pv), pvmetadatacopies,
-                                    pvmetadatasize, 0, &mdas))) {
+                                    pv_pe_size(existing_pv),
+                                    arg_int64_value(cmd, labelsector_ARG,
+                                                    DEFAULT_LABELSECTOR),
+                                    pvmetadatacopies, pvmetadatasize, 0))) {
                        log_error("Failed to setup physical volume \"%s\"",
                                  pv_dev_name(existing_pv));
                        if (change_made)
@@ -153,9 +151,7 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
 
                log_very_verbose("Writing physical volume data to disk \"%s\"",
                                 pv_dev_name(pv));
-               if (!(pv_write(cmd, pv, &mdas,
-                              arg_int64_value(cmd, labelsector_ARG,
-                                              DEFAULT_LABELSECTOR)))) {
+               if (!(pv_write(cmd, pv, 0))) {
                        log_error("Failed to write physical volume \"%s\"",
                                  pv_dev_name(pv));
                        log_error("Use pvcreate and vgcfgrestore to repair "
@@ -164,7 +160,6 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
                }
                log_verbose("Physical volume \"%s\" successfully created",
                            pv_dev_name(pv));
-
        }
 
        log_verbose("Deleting existing metadata for VG %s", vg_name);
@@ -191,7 +186,7 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
                          "archived metadata.");
                return ECMD_FAILED;
        }
-       log_print("Volume group %s successfully converted", vg_name);
+       log_print_unless_silent("Volume group %s successfully converted", vg_name);
 
        backup(vg);
 
index 49574f335595a1b8f8d129b5e5111bc5121ae5dd..2b9fb2f0c172c07a77e178ed68644e479a859a4a 100644 (file)
@@ -49,6 +49,8 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
        if (vgcreate_params_validate(cmd, &vp_new))
            return EINVALID_CMD_LINE;
 
+       lvmcache_seed_infos_from_lvmetad(cmd);
+
        /* Create the new VG */
        vg = vg_create(cmd, vp_new.vg_name);
        if (vg_read_error(vg)) {
@@ -56,7 +58,7 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
                        log_error("A volume group called %s already exists.", vp_new.vg_name);
                else
                        log_error("Can't get lock for %s.", vp_new.vg_name);
-               free_vg(vg);
+               release_vg(vg);
                return ECMD_FAILED;
        }
 
@@ -74,7 +76,7 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
        }
 
        /* attach the pv's */
-       if (!vg_extend(vg, argc, argv, &pp))
+       if (!vg_extend(vg, argc, (const char* const*)argv, &pp))
                goto_bad;
 
        if (vp_new.max_lv != vg->max_lv)
@@ -117,16 +119,16 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
 
        backup(vg);
 
-       log_print("%s%colume group \"%s\" successfully created",
-                 clustered_message, *clustered_message ? 'v' : 'V', vg->name);
+       log_print_unless_silent("%s%colume group \"%s\" successfully created",
+                               clustered_message, *clustered_message ? 'v' : 'V', vg->name);
 
-       free_vg(vg);
+       release_vg(vg);
        return ECMD_PROCESSED;
 
 bad:
        unlock_vg(cmd, VG_ORPHANS);
 bad_orphan:
-       free_vg(vg);
+       release_vg(vg);
        unlock_vg(cmd, vp_new.vg_name);
        return ECMD_FAILED;
 }
index a1043d2510cda2f4dfc4c4c22c36badc5baa2c4f..c573619ded1bf98ef3ed7b1928698448a1b13905 100644 (file)
@@ -44,7 +44,7 @@ static int vgexport_single(struct cmd_context *cmd __attribute__((unused)),
 
        backup(vg);
 
-       log_print("Volume group \"%s\" successfully exported", vg->name);
+       log_print_unless_silent("Volume group \"%s\" successfully exported", vg->name);
 
        return ECMD_PROCESSED;
 
index a0c166b065a218fd2093d77bd2dd903ab1d6e1a5..2ce7edbc7fe8f4eb03ffff0c2f7acea3c783c86d 100644 (file)
@@ -40,7 +40,7 @@ static int _restore_pv(struct volume_group *vg, char *pv_name)
 
 int vgextend(struct cmd_context *cmd, int argc, char **argv)
 {
-       char *vg_name;
+       const char *vg_name;
        struct volume_group *vg = NULL;
        int r = ECMD_FAILED;
        struct pvcreate_params pp;
@@ -66,13 +66,18 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
                return EINVALID_CMD_LINE;
        }
 
-       if (arg_count(cmd, restoremissing_ARG))
-               cmd->handles_missing_pvs = 1;
+       /*
+        * It is always ok to add new PVs to a VG - even if there are
+        * missing PVs.  No LVs are affected by this operation, but
+        * repair processes - particularly for RAID segtypes - can
+        * be facilitated.
+        */
+       cmd->handles_missing_pvs = 1;
 
        log_verbose("Checking for volume group \"%s\"", vg_name);
        vg = vg_read_for_update(cmd, vg_name, NULL, 0);
        if (vg_read_error(vg)) {
-               free_vg(vg);
+               release_vg(vg);
                stack;
                return ECMD_FAILED;
        }
@@ -92,7 +97,7 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
        } else { /* no --restore, normal vgextend */
                if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE)) {
                        log_error("Can't get lock for orphan PVs");
-                       unlock_and_free_vg(cmd, vg, vg_name);
+                       unlock_and_release_vg(cmd, vg, vg_name);
                        return ECMD_FAILED;
                }
 
@@ -107,7 +112,7 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
                }
 
                /* extend vg */
-               if (!vg_extend(vg, argc, argv, &pp))
+               if (!vg_extend(vg, argc, (const char* const*)argv, &pp))
                        goto_bad;
 
                if (arg_count(cmd, metadataignore_ARG) &&
@@ -129,12 +134,12 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
                goto_bad;
 
        backup(vg);
-       log_print("Volume group \"%s\" successfully extended", vg_name);
+       log_print_unless_silent("Volume group \"%s\" successfully extended", vg_name);
        r = ECMD_PROCESSED;
 
 bad:
        if (!arg_count(cmd, restoremissing_ARG))
                unlock_vg(cmd, VG_ORPHANS);
-       unlock_and_free_vg(cmd, vg, vg_name);
+       unlock_and_release_vg(cmd, vg, vg_name);
        return r;
 }
index 284f53617cc59620a8a46ccaccdc46f61d978acd..5badcb5a63bd701511a807e50b9b409c72a4f8ce 100644 (file)
@@ -48,7 +48,7 @@ static int vgimport_single(struct cmd_context *cmd __attribute__((unused)),
 
        backup(vg);
 
-       log_print("Volume group \"%s\" successfully imported", vg->name);
+       log_print_unless_silent("Volume group \"%s\" successfully imported", vg->name);
 
        return ECMD_PROCESSED;
 
index 391764f9a8b31d0be12fbe6e0d676c8843edc5d2..2cecb059ad2be724858c333f57516b837543cdba 100644 (file)
@@ -22,7 +22,7 @@ static struct volume_group *_vgmerge_vg_read(struct cmd_context *cmd,
        log_verbose("Checking for volume group \"%s\"", vg_name);
        vg = vg_read_for_update(cmd, vg_name, NULL, 0);
        if (vg_read_error(vg)) {
-               free_vg(vg);
+               release_vg(vg);
                return NULL;
        }
        return vg;
@@ -54,7 +54,7 @@ static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
                vg_to = _vgmerge_vg_read(cmd, vg_name_to);
                if (!vg_to) {
                        stack;
-                       unlock_and_free_vg(cmd, vg_from, vg_name_from);
+                       unlock_and_release_vg(cmd, vg_from, vg_name_from);
                        return ECMD_FAILED;
                }
        } else {
@@ -67,7 +67,7 @@ static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
                vg_from = _vgmerge_vg_read(cmd, vg_name_from);
                if (!vg_from) {
                        stack;
-                       unlock_and_free_vg(cmd, vg_to, vg_name_to);
+                       unlock_and_release_vg(cmd, vg_to, vg_name_to);
                        return ECMD_FAILED;
                }
        }
@@ -80,7 +80,8 @@ static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
        if (!archive(vg_from) || !archive(vg_to))
                goto_bad;
 
-       drop_cached_metadata(vg_from);
+       if (!drop_cached_metadata(vg_from))
+               stack;
 
        /* Merge volume groups */
        dm_list_iterate_items_safe(pvl, tpvl, &vg_from->pvs) {
@@ -147,23 +148,23 @@ static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
        /* FIXME Remove /dev/vgfrom */
 
        backup(vg_to);
-       log_print("Volume group \"%s\" successfully merged into \"%s\"",
-                 vg_from->name, vg_to->name);
+       log_print_unless_silent("Volume group \"%s\" successfully merged into \"%s\"",
+                               vg_from->name, vg_to->name);
        r = ECMD_PROCESSED;
 bad:
-       if (lock_vg_from_first) {
-               unlock_and_free_vg(cmd, vg_to, vg_name_to);
-               unlock_and_free_vg(cmd, vg_from, vg_name_from);
-       } else {
-               unlock_and_free_vg(cmd, vg_from, vg_name_from);
-               unlock_and_free_vg(cmd, vg_to, vg_name_to);
-       }
+       /*
+        * Note: as vg_to is referencing moved elements from vg_from
+        * the order of release_vg calls is mandatory.
+        */
+       unlock_and_release_vg(cmd, vg_to, vg_name_to);
+       unlock_and_release_vg(cmd, vg_from, vg_name_from);
+
        return r;
 }
 
 int vgmerge(struct cmd_context *cmd, int argc, char **argv)
 {
-       char *vg_name_to, *vg_name_from;
+       const char *vg_name_to, *vg_name_from;
        int opt = 0;
        int ret = 0, ret_max = 0;
 
index 4aa8f01e68acab18f69bdc155ee18e394bce0cac..1b04a492e430a34edc289b4ea85b873fd32a2c53 100644 (file)
@@ -14,7 +14,6 @@
  */
 
 #include "tools.h"
-#include "lv_alloc.h"
 
 static int _remove_pv(struct volume_group *vg, struct pv_list *pvl, int silent)
 {
@@ -40,91 +39,7 @@ static int _remove_pv(struct volume_group *vg, struct pv_list *pvl, int silent)
        vg->free_count -= pvl->pv->pe_count;
        vg->extent_count -= pvl->pv->pe_count;
        del_pvl_from_vgs(vg, pvl);
-
-       return 1;
-}
-
-static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv,
-                     int *list_unsafe, struct dm_list *lvs_changed)
-{
-       struct lv_segment *snap_seg;
-       struct dm_list *snh, *snht;
-       struct logical_volume *cow;
-       struct lv_list *lvl;
-       struct lvinfo info;
-       int first = 1;
-
-       log_verbose("%s/%s has missing extents: removing (including "
-                   "dependencies)", lv->vg->name, lv->name);
-
-       /* FIXME Cope properly with stacked devices & snapshots. */
-
-       /* If snapshot device is missing, deactivate origin. */
-       if (lv_is_cow(lv) && (snap_seg = find_cow(lv))) {
-               log_verbose("Deactivating (if active) logical volume %s "
-                           "(origin of %s)", snap_seg->origin->name, lv->name);
-
-               if (!test_mode() && !deactivate_lv(cmd, snap_seg->origin)) {
-                       log_error("Failed to deactivate LV %s",
-                                 snap_seg->origin->name);
-                       return 0;
-               }
-
-               /* Use the origin LV */
-               lv = snap_seg->origin;
-       }
-
-       /* Remove snapshot dependencies */
-       dm_list_iterate_safe(snh, snht, &lv->snapshot_segs) {
-               snap_seg = dm_list_struct_base(snh, struct lv_segment,
-                                           origin_list);
-               cow = snap_seg->cow;
-
-               if (first && !test_mode() &&
-                   !deactivate_lv(cmd, snap_seg->origin)) {
-                       log_error("Failed to deactivate LV %s",
-                                 snap_seg->origin->name);
-                       return 0;
-               }
-
-               *list_unsafe = 1;       /* May remove caller's lvht! */
-               if (!vg_remove_snapshot(cow))
-                       return_0;
-               log_verbose("Removing LV %s from VG %s", cow->name,
-                           lv->vg->name);
-               if (!lv_remove(cow))
-                       return_0;
-
-               first = 0;
-       }
-
-       /*
-        * If LV is active, replace it with error segment
-        * and add to list of LVs to be removed later.
-        * Doesn't apply to snapshots/origins yet - they're already deactivated.
-        */
-       /*
-        * If the LV is a part of mirror segment,
-        * the mirrored LV also should be cleaned up.
-        * Clean-up is currently done by caller (_make_vg_consistent()).
-        */
-       if ((lv_info(cmd, lv, 0, &info, 0, 0) && info.exists) ||
-           find_mirror_seg(first_seg(lv))) {
-               if (!replace_lv_with_error_segment(lv))
-                       return_0;
-
-               if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl)))) {
-                       log_error("lv_list alloc failed");
-                       return 0;
-               }
-               lvl->lv = lv;
-               dm_list_add(lvs_changed, &lvl->list);
-       } else {
-               /* Remove LV immediately. */
-               log_verbose("Removing LV %s from VG %s", lv->name, lv->vg->name);
-               if (!lv_remove(lv))
-                       return_0;
-       }
+       free_pv_fid(pvl->pv);
 
        return 1;
 }
@@ -144,8 +59,8 @@ static int _consolidate_vg(struct cmd_context *cmd, struct volume_group *vg)
 
        if (!r) {
                cmd->handles_missing_pvs = 1;
-               log_warn("WARNING: There are still partial LVs in VG %s.", vg->name);
-               log_warn("To remove them unconditionally use: vgreduce --removemissing --force.");
+               log_error("There are still partial LVs in VG %s.", vg->name);
+               log_error("To remove them unconditionally use: vgreduce --removemissing --force.");
                log_warn("Proceeding to remove empty missing PVs.");
        }
 
@@ -161,215 +76,41 @@ static int _consolidate_vg(struct cmd_context *cmd, struct volume_group *vg)
 
 static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
 {
-       struct dm_list *pvh, *pvht;
-       struct dm_list *lvh, *lvht;
-       struct pv_list *pvl;
-       struct lv_list *lvl, *lvl2, *lvlt;
+       struct lv_list *lvl;
        struct logical_volume *lv;
-       struct physical_volume *pv;
-       struct lv_segment *seg, *mirrored_seg;
-       unsigned s;
-       uint32_t mimages, remove_log;
-       int list_unsafe, only_mirror_images_found;
-       DM_LIST_INIT(lvs_changed);
-       only_mirror_images_found = 1;
-
-       /* Deactivate & remove necessary LVs */
-      restart_loop:
-       list_unsafe = 0;        /* Set if we delete a different list-member */
-
-       dm_list_iterate_safe(lvh, lvht, &vg->lvs) {
-               lv = dm_list_item(lvh, struct lv_list)->lv;
-
-               /* Are any segments of this LV on missing PVs? */
-               dm_list_iterate_items(seg, &lv->segments) {
-                       for (s = 0; s < seg->area_count; s++) {
-                               if (seg_type(seg, s) != AREA_PV)
-                                       continue;
-
-                               /* FIXME Also check for segs on deleted LVs (incl pvmove) */
-
-                               pv = seg_pv(seg, s);
-                               if (!pv || !pv_dev(pv) ||
-                                   is_missing_pv(pv)) {
-                                       if (arg_count(cmd, mirrorsonly_ARG) &&
-                                           !(lv->status & MIRROR_IMAGE)) {
-                                               log_error("Non-mirror-image LV %s found: can't remove.", lv->name);
-                                               only_mirror_images_found = 0;
-                                               continue;
-                                       }
-                                       if (!_remove_lv(cmd, lv, &list_unsafe, &lvs_changed))
-                                               return_0;
-                                       if (list_unsafe)
-                                               goto restart_loop;
-                               }
-                       }
-               }
-       }
-
-       if (!only_mirror_images_found) {
-               log_error("Aborting because --mirrorsonly was specified.");
-               return 0;
-       }
 
-       /*
-        * Remove missing PVs. FIXME: This duplicates _consolidate_vg above,
-        * but we cannot use that right now, since the LV removal code in this
-        * function leaves the VG in a "somewhat inconsistent" state and
-        * _consolidate_vg doesn't like that -- specifically, mirrors are fixed
-        * up *after* the PVs are removed. All this should be gradually
-        * superseded by lvconvert --repair.
-        */
-       dm_list_iterate_safe(pvh, pvht, &vg->pvs) {
-               pvl = dm_list_item(pvh, struct pv_list);
-               if (pvl->pv->dev && !is_missing_pv(pvl->pv))
-                       continue;
-               if (!_remove_pv(vg, pvl, 0))
-                       return_0;
-       }
+       cmd->partial_activation = 1;
 
-       /* FIXME Recovery.  For now people must clean up by hand. */
+ restart:
+       vg_mark_partial_lvs(vg, 1);
 
-       if (!dm_list_empty(&lvs_changed)) {
-               if (!vg_write(vg)) {
-                       log_error("Failed to write out a consistent VG for %s",
-                                 vg->name);
-                       return 0;
-               }
+       dm_list_iterate_items(lvl, &vg->lvs) {
+               lv = lvl->lv;
 
-               if (!test_mode()) {
-                       /* Suspend lvs_changed */
-                       if (!suspend_lvs(cmd, &lvs_changed)) {
-                               stack;
-                               vg_revert(vg);
-                               return 0;
-                       }
-               }
-
-               if (!vg_commit(vg)) {
-                       log_error("Failed to commit consistent VG for %s",
-                                 vg->name);
-                       vg_revert(vg);
-                       return 0;
-               }
-
-               if (!test_mode()) {
-                       if (!resume_lvs(cmd, &lvs_changed)) {
-                               log_error("Failed to resume LVs using error segments.");
-                               return 0;
-                       }
-               }
-
-  lvs_changed_altered:
-               /* Remove lost mirror images from mirrors */
-               dm_list_iterate_items(lvl, &vg->lvs) {
-  mirrored_seg_altered:
-                       mirrored_seg = first_seg(lvl->lv);
-                       if (!seg_is_mirrored(mirrored_seg))
-                               continue;
-
-                       mimages = mirrored_seg->area_count;
-                       remove_log = 0;
-
-                       for (s = 0; s < mirrored_seg->area_count; s++) {
-                               dm_list_iterate_items_safe(lvl2, lvlt, &lvs_changed) {
-                                       if (seg_type(mirrored_seg, s) != AREA_LV ||
-                                           lvl2->lv != seg_lv(mirrored_seg, s))
-                                               continue;
-                                       dm_list_del(&lvl2->list);
-                                       if (!shift_mirror_images(mirrored_seg, s))
-                                               return_0;
-                                       mimages--;      /* FIXME Assumes uniqueness */
-                               }
-                       }
-
-                       if (mirrored_seg->log_lv) {
-                               dm_list_iterate_items(seg, &mirrored_seg->log_lv->segments) {
-                                       /* FIXME: The second test shouldn't be required */
-                                       if ((seg->segtype ==
-                                            get_segtype_from_string(vg->cmd, "error"))) {
-                                               log_print("The log device for %s/%s has failed.",
-                                                         vg->name, mirrored_seg->lv->name);
-                                               remove_log = 1;
-                                               break;
-                                       }
-                                       if (!strcmp(seg->segtype->name, "error")) {
-                                               log_print("Log device for %s/%s has failed.",
-                                                         vg->name, mirrored_seg->lv->name);
-                                               remove_log = 1;
-                                               break;
-                                       }
-                               }
-                       }
-
-                       if ((mimages != mirrored_seg->area_count) || remove_log){
-                               if (!reconfigure_mirror_images(mirrored_seg, mimages,
-                                                              NULL, remove_log))
+               /* Are any segments of this LV on missing PVs? */
+               if (lv->status & PARTIAL_LV) {
+                       if (lv->status & MIRRORED) {
+                               if (!mirror_remove_missing(cmd, lv, 1))
                                        return_0;
-
-                               if (!vg_write(vg)) {
-                                       log_error("Failed to write out updated "
-                                                 "VG for %s", vg->name);
-                                       return 0;
-                               }
-               
-                               if (!vg_commit(vg)) {
-                                       log_error("Failed to commit updated VG "
-                                                 "for %s", vg->name);
-                                       vg_revert(vg);
-                                       return 0;
-                               }
-
-                               /* mirrored LV no longer has valid mimages.
-                                * So add it to lvs_changed for removal.
-                                * For this LV may be an area of other mirror,
-                                * restart the loop. */
-                               if (!mimages) {
-                                       if (!_remove_lv(cmd, lvl->lv,
-                                                &list_unsafe, &lvs_changed))
-                                               return_0;
-                                       goto lvs_changed_altered;
-                               }
-
-                               /* As a result of reconfigure_mirror_images(),
-                                * first_seg(lv) may now be different seg.
-                                * e.g. a temporary layer might be removed.
-                                * So check the mirrored_seg again. */
-                               goto mirrored_seg_altered;
+                               goto restart;
                        }
-               }
 
-               /* Deactivate error LVs */
-               if (!test_mode()) {
-                       dm_list_iterate_items_safe(lvl, lvlt, &lvs_changed) {
-                               log_verbose("Deactivating (if active) logical volume %s",
-                                           lvl->lv->name);
-
-                               if (!deactivate_lv(cmd, lvl->lv)) {
-                                       log_error("Failed to deactivate LV %s",
-                                                 lvl->lv->name);
-                                       /*
-                                        * We failed to deactivate.
-                                        * Probably because this was a mirror log.
-                                        * Don't try to lv_remove it.
-                                        * Continue work on others.
-                                        */
-                                       dm_list_del(&lvl->list);
-                               }
+                       if (arg_count(cmd, mirrorsonly_ARG) &&!(lv->status & MIRRORED)) {
+                               log_error("Non-mirror-image LV %s found: can't remove.", lv->name);
+                               continue;
                        }
-               }
 
-               /* Remove remaining LVs */
-               dm_list_iterate_items(lvl, &lvs_changed) {
-                       log_verbose("Removing LV %s from VG %s", lvl->lv->name,
-                                   lvl->lv->vg->name);
-                               /* Skip LVs already removed by mirror code */
-                               if (find_lv_in_vg(vg, lvl->lv->name) &&
-                                   !lv_remove(lvl->lv))
-                                       return_0;
+                       if (!lv_is_visible(lv))
+                               continue;
+                       log_warn("Removing partial LV %s.", lv->name);
+                       if (!lv_remove_with_dependencies(cmd, lv, DONT_PROMPT, 0))
+                               return_0;
+                       goto restart;
                }
        }
 
+       _consolidate_vg(cmd, vg);
+
        return 1;
 }
 
@@ -383,6 +124,11 @@ static int _vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
        int r = ECMD_FAILED;
        const char *name = pv_dev_name(pv);
 
+       if (!vg) {
+               log_error(INTERNAL_ERROR "VG is NULL.");
+               return ECMD_FAILED;
+       }
+
        if (pv_pe_alloc_count(pv)) {
                log_error("Physical volume \"%s\" still in use", name);
                return ECMD_FAILED;
@@ -438,7 +184,7 @@ static int _vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
                goto bad;
        }
 
-       if (!pv_write(cmd, pv, NULL, INT64_C(-1))) {
+       if (!pv_write(cmd, pv, 0)) {
                log_error("Failed to clear metadata from physical "
                          "volume \"%s\" "
                          "after removal from \"%s\"", name, vg->name);
@@ -447,21 +193,24 @@ static int _vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
 
        backup(vg);
 
-       log_print("Removed \"%s\" from volume group \"%s\"", name, vg->name);
+       log_print_unless_silent("Removed \"%s\" from volume group \"%s\"", name, vg->name);
        r = ECMD_PROCESSED;
 bad:
-       unlock_and_free_vg(cmd, orphan_vg, VG_ORPHANS);
+       if (pvl)
+               free_pv_fid(pvl->pv);
+       unlock_and_release_vg(cmd, orphan_vg, VG_ORPHANS);
        return r;
 }
 
 int vgreduce(struct cmd_context *cmd, int argc, char **argv)
 {
        struct volume_group *vg;
-       char *vg_name;
+       const char *vg_name;
        int ret = ECMD_FAILED;
        int fixed = 1;
        int repairing = arg_count(cmd, removemissing_ARG);
        int saved_ignore_suspended_devices = ignore_suspended_devices();
+       int locked = 0;
 
        if (!argc && !repairing) {
                log_error("Please give volume group name and "
@@ -469,7 +218,7 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
                return EINVALID_CMD_LINE;
        }
        
-       if (!argc && repairing) {
+       if (!argc) { /* repairing */
                log_error("Please give volume group name");
                return EINVALID_CMD_LINE;
        }
@@ -516,6 +265,8 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
            && !arg_count(cmd, removemissing_ARG))
                goto_out;
 
+       locked = !vg_read_error(vg);
+
        if (repairing) {
                if (!vg_read_error(vg) && !vg_missing_pv_count(vg)) {
                        log_error("Volume group \"%s\" is already consistent",
@@ -524,13 +275,14 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
                        goto out;
                }
 
-               free_vg(vg);
+               release_vg(vg);
                log_verbose("Trying to open VG %s for recovery...", vg_name);
 
                vg = vg_read_for_update(cmd, vg_name, NULL,
                                        READ_ALLOW_INCONSISTENT
                                        | READ_ALLOW_EXPORTED);
 
+               locked |= !vg_read_error(vg);
                if (vg_read_error(vg) && vg_read_error(vg) != FAILED_READ_ONLY
                    && vg_read_error(vg) != FAILED_INCONSISTENT)
                        goto_out;
@@ -552,8 +304,8 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
                backup(vg);
 
                if (fixed) {
-                       log_print("Wrote out consistent volume group %s",
-                                 vg_name);
+                       log_print_unless_silent("Wrote out consistent volume group %s",
+                                               vg_name);
                        ret = ECMD_PROCESSED;
                } else
                        ret = ECMD_FAILED;
@@ -570,7 +322,10 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
        }
 out:
        init_ignore_suspended_devices(saved_ignore_suspended_devices);
-       unlock_and_free_vg(cmd, vg, vg_name);
+       if (locked)
+               unlock_vg(cmd, vg_name);
+
+       release_vg(vg);
 
        return ret;
 
index 67e3767b43adef8486fef9b349f9b017180e3a6e..6804f2af98f3cc76ce7b61026009e859b25d79ca 100644 (file)
@@ -29,7 +29,7 @@ static int vgremove_single(struct cmd_context *cmd, const char *vg_name,
 
        lv_count = vg_visible_lvs(vg);
 
-       force = arg_count(cmd, force_ARG);
+       force = (force_t) arg_count(cmd, force_ARG);
        if (lv_count) {
                if (force == PROMPT) {
                        if ((missing = vg_missing_pv_count(vg)))
index 98be9a960083bedba2e9671309c4ca48e296ce4f..b4766024811455a957d92f1b889badb825356920 100644 (file)
@@ -25,7 +25,7 @@ static struct volume_group *_get_old_vg_for_rename(struct cmd_context *cmd,
           nevertheless. */
        vg = vg_read_for_update(cmd, vg_name_old, vgid, READ_ALLOW_EXPORTED);
        if (vg_read_error(vg)) {
-               free_vg(vg);
+               release_vg(vg);
                return_NULL;
        }
 
@@ -63,7 +63,7 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path,
        int found_id = 0;
        struct dm_list *vgids;
        struct str_list *sl;
-       char *vg_name_new;
+       const char *vg_name_new;
        const char *vgid = NULL, *vg_name, *vg_name_old;
        char old_path[NAME_LEN], new_path[NAME_LEN];
        struct volume_group *vg = NULL;
@@ -79,6 +79,10 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path,
 
        log_verbose("Checking for existing volume group \"%s\"", vg_name_old);
 
+       /* populate lvmcache */
+       if (!lvmetad_vg_list_to_lvmcache(cmd))
+               stack;
+
        /* Avoid duplicates */
        if (!(vgids = get_vgids(cmd, 0)) || dm_list_empty(vgids)) {
                log_error("No complete volume groups found");
@@ -87,7 +91,7 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path,
 
        dm_list_iterate_items(sl, vgids) {
                vgid = sl->str;
-               if (!vgid || !(vg_name = vgname_from_vgid(NULL, vgid)))
+               if (!vgid || !(vg_name = lvmcache_vgname_from_vgid(NULL, vgid)))
                        continue;
                if (!strcmp(vg_name, vg_name_old)) {
                        if (match) {
@@ -102,7 +106,7 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path,
        log_suppress(2);
        found_id = id_read_format(&id, vg_name_old);
        log_suppress(0);
-       if (found_id && (vg_name = vgname_from_vgid(cmd->mem, (char *)id.uuid))) {
+       if (found_id && (vg_name = lvmcache_vgname_from_vgid(cmd->mem, (char *)id.uuid))) {
                vg_name_old = vg_name;
                vgid = (char *)id.uuid;
        } else
@@ -117,7 +121,7 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path,
                        return_0;
 
                if (!_lock_new_vg_for_rename(cmd, vg_name_new)) {
-                       unlock_and_free_vg(cmd, vg, vg_name_old);
+                       unlock_and_release_vg(cmd, vg, vg_name_old);
                        return_0;
                }
        } else {
@@ -135,7 +139,8 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path,
                goto error;
 
        /* Remove references based on old name */
-       drop_cached_metadata(vg);
+       if (!drop_cached_metadata(vg))
+               stack;
 
        /* Change the volume group name */
        vg_rename(cmd, vg, vg_name_new);
@@ -164,17 +169,20 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path,
                }
        }
 
-       backup(vg);
-       backup_remove(cmd, vg_name_old);
+       if (!backup(vg))
+               stack;
+       if (!backup_remove(cmd, vg_name_old))
+               stack;
 
        unlock_vg(cmd, vg_name_new);
-       unlock_and_free_vg(cmd, vg, vg_name_old);
+       unlock_and_release_vg(cmd, vg, vg_name_old);
 
-       log_print("Volume group \"%s\" successfully renamed to \"%s\"",
-                 vg_name_old, vg_name_new);
+       log_print_unless_silent("Volume group \"%s\" successfully renamed to \"%s\"",
+                               vg_name_old, vg_name_new);
 
        /* FIXME lvmcache corruption - vginfo duplicated instead of renamed */
-       persistent_filter_wipe(cmd->filter);
+       if (cmd->filter->wipe)
+               cmd->filter->wipe(cmd->filter);
        lvmcache_destroy(cmd, 1);
 
        return 1;
@@ -182,9 +190,9 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path,
       error:
        if (lock_vg_old_first) {
                unlock_vg(cmd, vg_name_new);
-               unlock_and_free_vg(cmd, vg, vg_name_old);
+               unlock_and_release_vg(cmd, vg, vg_name_old);
        } else {
-               unlock_and_free_vg(cmd, vg, vg_name_old);
+               unlock_and_release_vg(cmd, vg, vg_name_old);
                unlock_vg(cmd, vg_name_new);
        }
        return 0;
index 4e12914c63fd78b157419d358773e862ca071d6b..99124ef1c4be7ff2a81d9bf320a121aced8a81f8 100644 (file)
@@ -19,9 +19,9 @@ static int vgscan_single(struct cmd_context *cmd, const char *vg_name,
                         struct volume_group *vg,
                         void *handle __attribute__((unused)))
 {
-       log_print("Found %svolume group \"%s\" using metadata type %s",
-                 vg_is_exported(vg) ? "exported " : "", vg_name,
-                 vg->fid->fmt->name);
+       log_print_unless_silent("Found %svolume group \"%s\" using metadata type %s",
+                               vg_is_exported(vg) ? "exported " : "", vg_name,
+                               vg->fid->fmt->name);
 
        check_current_backup(vg);
 
@@ -42,10 +42,23 @@ int vgscan(struct cmd_context *cmd, int argc, char **argv)
                return ECMD_FAILED;
        }
 
-       persistent_filter_wipe(cmd->filter);
+       if (cmd->filter->wipe)
+               cmd->filter->wipe(cmd->filter);
        lvmcache_destroy(cmd, 1);
 
-       log_print("Reading all physical volumes.  This may take a while...");
+       if (arg_count(cmd, cache_ARG)) {
+               if (lvmetad_active()) {
+                       if (!lvmetad_pvscan_all_devs(cmd, NULL))
+                               return ECMD_FAILED;
+               }
+               else {
+                       log_error("Cannot proceed since lvmetad is not active.");
+                       unlock_vg(cmd, VG_GLOBAL);
+                       return ECMD_FAILED;
+               }
+       }
+
+       log_print_unless_silent("Reading all physical volumes.  This may take a while...");
 
        maxret = process_each_vg(cmd, argc, argv, 0, NULL,
                                 &vgscan_single);
index bd2f0ab31e7b59d7dadebeee6c3a6b2fb741a64d..3bbb9fafb0c3f012ce8fbbc80f5deb7ec4179c94 100644 (file)
@@ -163,7 +163,7 @@ static int _move_mirrors(struct volume_group *vg_from,
 {
        struct dm_list *lvh, *lvht;
        struct logical_volume *lv;
-       struct lv_segment *seg;
+       struct lv_segment *seg, *log_seg;
        unsigned s, seg_in, log_in;
 
        dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) {
@@ -179,7 +179,20 @@ static int _move_mirrors(struct volume_group *vg_from,
                        if (_lv_is_in_vg(vg_to, seg_lv(seg, s)))
                            seg_in++;
 
-               log_in = (!seg->log_lv || _lv_is_in_vg(vg_to, seg->log_lv));
+               log_in = !seg->log_lv;
+               if (seg->log_lv) {
+                       log_seg = first_seg(seg->log_lv);
+                       if (seg_is_mirrored(log_seg)) {
+                               log_in = 1;
+
+                               /* Ensure each log dev is in vg_to */
+                               for (s = 0; s < log_seg->area_count; s++)
+                                       log_in = log_in &&
+                                               _lv_is_in_vg(vg_to,
+                                                            seg_lv(log_seg, s));
+                       } else
+                               log_in = _lv_is_in_vg(vg_to, seg->log_lv);
+               }
 
                if ((seg_in && seg_in < seg->area_count) ||
                    (seg_in && seg->log_lv && !log_in) ||
@@ -224,16 +237,16 @@ static struct volume_group *_vgsplit_to(struct cmd_context *cmd,
        vg_to = vg_create(cmd, vg_name_to);
        if (vg_read_error(vg_to) == FAILED_LOCKING) {
                log_error("Can't get lock for %s", vg_name_to);
-               free_vg(vg_to);
+               release_vg(vg_to);
                return NULL;
        }
        if (vg_read_error(vg_to) == FAILED_EXIST) {
                *existing_vg = 1;
-               free_vg(vg_to);
+               release_vg(vg_to);
                vg_to = vg_read_for_update(cmd, vg_name_to, NULL, 0);
 
                if (vg_read_error(vg_to)) {
-                       free_vg(vg_to);
+                       release_vg(vg_to);
                        stack;
                        return NULL;
                }
@@ -259,7 +272,7 @@ static struct volume_group *_vgsplit_from(struct cmd_context *cmd,
 
        vg_from = vg_read_for_update(cmd, vg_name_from, NULL, 0);
        if (vg_read_error(vg_from)) {
-               free_vg(vg_from);
+               release_vg(vg_from);
                return NULL;
        }
        return vg_from;
@@ -281,7 +294,7 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
 {
        struct vgcreate_params vp_new;
        struct vgcreate_params vp_def;
-       char *vg_name_from, *vg_name_to;
+       const char *vg_name_from, *vg_name_to;
        struct volume_group *vg_to = NULL, *vg_from = NULL;
        int opt;
        int existing_vg = 0;
@@ -334,7 +347,7 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
 
                vg_to = _vgsplit_to(cmd, vg_name_to, &existing_vg);
                if (!vg_to) {
-                       unlock_and_free_vg(cmd, vg_from, vg_name_from);
+                       unlock_and_release_vg(cmd, vg_from, vg_name_from);
                        stack;
                        return ECMD_FAILED;
                }
@@ -346,7 +359,7 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
                }
                vg_from = _vgsplit_from(cmd, vg_name_from);
                if (!vg_from) {
-                       unlock_and_free_vg(cmd, vg_to, vg_name_to);
+                       unlock_and_release_vg(cmd, vg_to, vg_name_to);
                        stack;
                        return ECMD_FAILED;
                }
@@ -395,7 +408,7 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
 
        /* Move PVs across to new structure */
        for (opt = 0; opt < argc; opt++) {
-               unescape_colons_and_at_signs(argv[opt], NULL, NULL);
+               dm_unescape_colons_and_at_signs(argv[opt], NULL, NULL);
                if (!move_pv(vg_from, vg_to, argv[opt]))
                        goto_bad;
        }
@@ -463,7 +476,7 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
         * Finally, remove the EXPORTED flag from the new VG and write it out.
         */
        if (!test_mode()) {
-               free_vg(vg_to);
+               release_vg(vg_to);
                vg_to = vg_read_for_update(cmd, vg_name_to, NULL,
                                           READ_ALLOW_EXPORTED);
                if (vg_read_error(vg_to)) {
@@ -480,19 +493,19 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
 
        backup(vg_to);
 
-       log_print("%s volume group \"%s\" successfully split from \"%s\"",
-                 existing_vg ? "Existing" : "New",
-                 vg_to->name, vg_from->name);
+       log_print_unless_silent("%s volume group \"%s\" successfully split from \"%s\"",
+                               existing_vg ? "Existing" : "New",
+                               vg_to->name, vg_from->name);
 
        r = ECMD_PROCESSED;
 
 bad:
-       if (lock_vg_from_first) {
-               unlock_and_free_vg(cmd, vg_to, vg_name_to);
-               unlock_and_free_vg(cmd, vg_from, vg_name_from);
-       } else {
-               unlock_and_free_vg(cmd, vg_from, vg_name_from);
-               unlock_and_free_vg(cmd, vg_to, vg_name_to);
-       }
+       /*
+        * vg_to references elements moved from vg_from
+        * so vg_to has to be freed first.
+        */
+       unlock_and_release_vg(cmd, vg_to, vg_name_to);
+       unlock_and_release_vg(cmd, vg_from, vg_name_from);
+
        return r;
 }
index 4d50ed3df39137fd2aad18e26657e00443eddf78..29af467bf93df37b54a6b796ca5415f4931ab66d 100644 (file)
@@ -18,17 +18,7 @@ KERNEL=="device-mapper", NAME="(DM_DIR)/control"
 
 SUBSYSTEM!="block", GOTO="dm_end"
 KERNEL!="dm-[0-9]*", GOTO="dm_end"
-
-# Set proper sbin path, /sbin has higher priority than /usr/sbin.
-ENV{DM_SBIN_PATH}="/sbin"
-TEST!="$env{DM_SBIN_PATH}/dmsetup", ENV{DM_SBIN_PATH}="/usr/sbin"
-TEST!="$env{DM_SBIN_PATH}/dmsetup", GOTO="dm_end"
-
-# Decode udev control flags and set environment variables appropriately.
-# These flags are encoded in DM_COOKIE variable that was introduced in
-# kernel version 2.6.31. Therefore, we can use this feature with
-# kernels >= 2.6.31 only.
-ENV{DM_COOKIE}=="?*", IMPORT{program}="$env{DM_SBIN_PATH}/dmsetup udevflags $env{DM_COOKIE}"
+(DM_EXEC_RULE)
 
 # Device created, major and minor number assigned - "add" event generated.
 # Table loaded - no event generated.
@@ -42,6 +32,12 @@ ENV{DM_COOKIE}=="?*", IMPORT{program}="$env{DM_SBIN_PATH}/dmsetup udevflags $env
 # is not recommended.
 ACTION!="add|change", GOTO="dm_end"
 
+# Decode udev control flags and set environment variables appropriately.
+# These flags are encoded in DM_COOKIE variable that was introduced in
+# kernel version 2.6.31. Therefore, we can use this feature with
+# kernels >= 2.6.31 only. Cookie is not decoded for remove event.
+ENV{DM_COOKIE}=="?*", IMPORT{program}="(DM_EXEC)/dmsetup udevflags $env{DM_COOKIE}"
+
 # Rule out easy-to-detect inappropriate events first.
 ENV{DISK_RO}=="1", GOTO="dm_disable"
 
@@ -91,8 +87,8 @@ ACTION=="add", ENV{DM_UDEV_RULES_VSN}!="1", ENV{DM_UDEV_PRIMARY_SOURCE_FLAG}!="1
 # so we also have to call dmsetup if the kernel version used
 # is in between these releases.
 TEST=="dm", ENV{DM_NAME}="$attr{dm/name}", ENV{DM_UUID}="$attr{dm/uuid}", ENV{DM_SUSPENDED}="$attr{dm/suspended}"
-TEST!="dm", IMPORT{program}="$env{DM_SBIN_PATH}/dmsetup info -j %M -m %m -c --nameprefixes --noheadings --rows -o name,uuid,suspended"
-ENV{DM_SUSPENDED}!="?*", IMPORT{program}="$env{DM_SBIN_PATH}/dmsetup info -j %M -m %m -c --nameprefixes --noheadings --rows -o suspended"
+TEST!="dm", IMPORT{program}="(DM_EXEC)/dmsetup info -j %M -m %m -c --nameprefixes --noheadings --rows -o name,uuid,suspended"
+ENV{DM_SUSPENDED}!="?*", IMPORT{program}="(DM_EXEC)/dmsetup info -j %M -m %m -c --nameprefixes --noheadings --rows -o suspended"
 
 # dmsetup tool provides suspended state information in textual
 # form with values "Suspended"/"Active". We translate it to
@@ -119,6 +115,11 @@ ENV{DM_UUID}=="mpath-?*", ENV{DM_ACTION}=="PATH_FAILED", GOTO="dm_disable"
 ENV{DM_UUID}=="CRYPT-TEMP-?*", GOTO="dm_disable"
 ENV{DM_UUID}!="?*", ENV{DM_NAME}=="temporary-cryptsetup-?*", GOTO="dm_disable"
 
+# Avoid processing and scanning a DM device in the other (foreign)
+# rules if it is in suspended state. However, we still keep 'disk'
+# and 'DM subsystem' related rules enabled in this case.
+ENV{DM_SUSPENDED}=="1", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="1"
+
 GOTO="dm_end"
 
 LABEL="dm_disable"
diff --git a/udev/11-dm-lvm.rules b/udev/11-dm-lvm.rules
deleted file mode 100644 (file)
index 8244464..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright (C) 2009 Red Hat, Inc. All rights reserved.
-#
-# This file is part of LVM2.
-
-# Udev rules for LVM.
-#
-# These rules create symlinks for LVM logical volumes in
-# /dev/VG directory (VG is an actual VG name). Some udev
-# environment variables are set (they can be used in later
-# rules as well):
-#   DM_LV_NAME - logical volume name
-#   DM_VG_NAME - volume group name
-#   DM_LV_LAYER - logical volume layer (blank if not set)
-
-# "add" event is processed on coldplug only!
-ACTION!="add|change", GOTO="lvm_end"
-ENV{DM_UDEV_RULES_VSN}!="?*", GOTO="lvm_end"
-ENV{DM_UUID}!="LVM-?*", GOTO="lvm_end"
-
-# Use DM name and split it up into its VG/LV/layer constituents.
-IMPORT{program}="$env{DM_SBIN_PATH}/dmsetup splitname --nameprefixes --noheadings --rows $env{DM_NAME}"
-
-ENV{DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG}=="1", GOTO="lvm_end"
-
-# Do not create symlinks for inappropriate subdevices.
-ENV{DM_LV_NAME}=="pvmove?*|?*_vorigin", GOTO="lvm_disable"
-ENV{DM_LV_LAYER}=="?*", GOTO="lvm_disable"
-
-# Create symlinks for top-level devices only.
-ENV{DM_VG_NAME}=="?*", ENV{DM_LV_NAME}=="?*", SYMLINK+="$env{DM_VG_NAME}/$env{DM_LV_NAME}", GOTO="lvm_end"
-
-LABEL="lvm_disable"
-ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}="1"
-ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="1"
-OPTIONS:="nowatch"
-
-LABEL="lvm_end"
diff --git a/udev/11-dm-lvm.rules.in b/udev/11-dm-lvm.rules.in
new file mode 100644 (file)
index 0000000..58ef210
--- /dev/null
@@ -0,0 +1,37 @@
+# Copyright (C) 2009 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+
+# Udev rules for LVM.
+#
+# These rules create symlinks for LVM logical volumes in
+# /dev/VG directory (VG is an actual VG name). Some udev
+# environment variables are set (they can be used in later
+# rules as well):
+#   DM_LV_NAME - logical volume name
+#   DM_VG_NAME - volume group name
+#   DM_LV_LAYER - logical volume layer (blank if not set)
+
+# "add" event is processed on coldplug only!
+ACTION!="add|change", GOTO="lvm_end"
+ENV{DM_UDEV_RULES_VSN}!="?*", GOTO="lvm_end"
+ENV{DM_UUID}!="LVM-?*", GOTO="lvm_end"
+
+# Use DM name and split it up into its VG/LV/layer constituents.
+IMPORT{program}="(DM_EXEC)/dmsetup splitname --nameprefixes --noheadings --rows $env{DM_NAME}"
+
+ENV{DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG}=="1", GOTO="lvm_end"
+
+# Do not create symlinks for inappropriate subdevices.
+ENV{DM_LV_NAME}=="pvmove?*|?*_vorigin", GOTO="lvm_disable"
+ENV{DM_LV_LAYER}=="?*", GOTO="lvm_disable"
+
+# Create symlinks for top-level devices only.
+ENV{DM_VG_NAME}=="?*", ENV{DM_LV_NAME}=="?*", SYMLINK+="$env{DM_VG_NAME}/$env{DM_LV_NAME}", GOTO="lvm_end"
+
+LABEL="lvm_disable"
+ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}="1"
+ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="1"
+OPTIONS:="nowatch"
+
+LABEL="lvm_end"
diff --git a/udev/13-dm-disk.rules b/udev/13-dm-disk.rules
deleted file mode 100644 (file)
index 271ca22..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2009 Red Hat, Inc. All rights reserved.
-#
-# This file is part of LVM2.
-
-# Udev rules for device-mapper devices.
-#
-# These rules create symlinks in /dev/disk directory.
-# Symlinks that depend on probing filesystem type,
-# label and uuid are created only if the device is not
-# suspended.
-
-# "add" event is processed on coldplug only!
-ACTION!="add|change", GOTO="dm_end"
-ENV{DM_UDEV_RULES_VSN}!="?*", GOTO="dm_end"
-ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}=="1", GOTO="dm_end"
-
-SYMLINK+="disk/by-id/dm-name-$env{DM_NAME}"
-ENV{DM_UUID}=="?*", SYMLINK+="disk/by-id/dm-uuid-$env{DM_UUID}"
-
-ENV{DM_SUSPENDED}=="1", GOTO="dm_end"
-
-IMPORT{program}="$env{DM_SBIN_PATH}/blkid -o udev -p $tempnode"
-ENV{DM_UDEV_LOW_PRIORITY_FLAG}=="1", OPTIONS="link_priority=-100"
-ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-uuid/$env{ID_FS_UUID_ENC}"
-ENV{ID_FS_USAGE}=="filesystem|other", ENV{ID_FS_LABEL_ENC}=="?*", SYMLINK+="disk/by-label/$env{ID_FS_LABEL_ENC}"
-
-LABEL="dm_end"
diff --git a/udev/13-dm-disk.rules.in b/udev/13-dm-disk.rules.in
new file mode 100644 (file)
index 0000000..1920260
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright (C) 2009 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+
+# Udev rules for device-mapper devices.
+#
+# These rules create symlinks in /dev/disk directory.
+# Symlinks that depend on probing filesystem type,
+# label and uuid are created only if the device is not
+# suspended.
+
+# "add" event is processed on coldplug only!
+ACTION!="add|change", GOTO="dm_end"
+ENV{DM_UDEV_RULES_VSN}!="?*", GOTO="dm_end"
+ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}=="1", GOTO="dm_end"
+
+SYMLINK+="disk/by-id/dm-name-$env{DM_NAME}"
+ENV{DM_UUID}=="?*", SYMLINK+="disk/by-id/dm-uuid-$env{DM_UUID}"
+
+ENV{DM_SUSPENDED}=="1", GOTO="dm_end"
+
+(BLKID_RULE)
+ENV{DM_UDEV_LOW_PRIORITY_FLAG}=="1", OPTIONS="link_priority=-100"
+ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-uuid/$env{ID_FS_UUID_ENC}"
+ENV{ID_FS_USAGE}=="filesystem|other", ENV{ID_FS_LABEL_ENC}=="?*", SYMLINK+="disk/by-label/$env{ID_FS_LABEL_ENC}"
+
+# Add inotify watch to track changes on this device.
+# Using the watch rule is not optimal - it generates a lot of spurious
+# and useless events whenever the device opened for read-write is closed.
+# The best would be to generete the event directly in the tool changing
+# relevant information so only relevant events will be processed
+# (like creating a filesystem, changing filesystem label etc.).
+#
+# But let's use this until we have something better...
+
+OPTIONS+="watch"
+
+LABEL="dm_end"
diff --git a/udev/69-dm-lvm-metad.rules.in b/udev/69-dm-lvm-metad.rules.in
new file mode 100644 (file)
index 0000000..706c03b
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+
+# Udev rules for LVM.
+#
+# Scan all block devices having a PV label for LVM metadata.
+# Store this information in LVMetaD (the LVM metadata daemon) and maintain LVM
+# metadata state for improved performance by avoiding further scans while
+# running subsequent LVM commands or while using lvm2app library.
+# Also, notify LVMetaD about any relevant block device removal.
+#
+# This rule is essential for having the information in LVMetaD up-to-date.
+# It also requires blkid to be called on block devices before so only devices
+# used as LVM PVs are processed (ID_FS_TYPE="LVM2_member" or "LVM1_member").
+
+SUBSYSTEM!="block", GOTO="lvm_end"
+(LVM_EXEC_RULE)
+
+# Device-mapper devices are processed only on change event or on supported synthesized event.
+KERNEL=="dm-[0-9]*", ENV{DM_UDEV_RULES_VSN}!="?*", GOTO="lvm_end"
+
+# Only process devices already marked as a PV - this requires blkid to be called before.
+ENV{ID_FS_TYPE}=="LVM2_member|LVM1_member", RUN+="(LVM_EXEC)/lvm pvscan --cache --activate ay --major $major --minor $minor"
+
+LABEL="lvm_end"
diff --git a/udev/95-dm-notify.rules b/udev/95-dm-notify.rules
deleted file mode 100644 (file)
index 72cc609..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright (C) 2009 Red Hat, Inc. All rights reserved.
-#
-# This file is part of LVM2.
-
-# Udev rules for device-mapper devices.
-#
-# These rules are responsible for sending a notification to a process
-# waiting for completion of udev rules. The process is identified by
-# a cookie value sent within "change" and "remove" events (the cookie
-# value is set before by that process for every action requested).
-
-ENV{DM_COOKIE}=="?*", RUN+="$env{DM_SBIN_PATH}/dmsetup udevcomplete $env{DM_COOKIE}"
diff --git a/udev/95-dm-notify.rules.in b/udev/95-dm-notify.rules.in
new file mode 100644 (file)
index 0000000..80d59d3
--- /dev/null
@@ -0,0 +1,12 @@
+# Copyright (C) 2009 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+
+# Udev rules for device-mapper devices.
+#
+# These rules are responsible for sending a notification to a process
+# waiting for completion of udev rules. The process is identified by
+# a cookie value sent within "change" and "remove" events (the cookie
+# value is set before by that process for every action requested).
+
+ENV{DM_COOKIE}=="?*", RUN+="(DM_EXEC)/dmsetup udevcomplete $env{DM_COOKIE}"
index 11635bbc2963c55218be5a0a4ec0b0e13aeed709..5c15bdb64812bc39ca666ec8c016f9e5f27c4b7d 100644 (file)
@@ -15,18 +15,39 @@ srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 top_builddir = @top_builddir@
 
+include $(top_builddir)/make.tmpl
+vpath %.rules $(srcdir)
+
 DM_RULES=10-dm.rules 13-dm-disk.rules 95-dm-notify.rules
 LVM_RULES=11-dm-lvm.rules
-DM_DIR=$(shell grep "\#define DM_DIR" $(top_srcdir)/libdm/misc/dm-ioctl.h | awk '{print $$3}')
+ifeq ("@BUILD_LVMETAD@", "yes")
+LVM_RULES+=69-dm-lvm-metad.rules
+endif
 
-CLEAN_TARGETS=10-dm.rules
-
-include $(top_builddir)/make.tmpl
+DM_DIR=$(shell grep "\#define DM_DIR" $(top_srcdir)/libdm/misc/dm-ioctl.h | awk '{print $$3}')
 
-vpath %.rules $(srcdir)
+ifeq ("@UDEV_RULE_EXEC_DETECTION@", "yes")
+SBIN=\$$env{DM_SBIN_PATH}
+DM_EXEC_RULE=ENV{DM_SBIN_PATH}=\"\/sbin\"\\nTEST!=\"\$$env{DM_SBIN_PATH}\/dmsetup\", ENV{DM_SBIN_PATH}=\"\/usr\/sbin\"
+DM_EXEC=\$$env{DM_SBIN_PATH}
+LVM_EXEC_RULE=ENV{LVM_SBIN_PATH}=\"\/sbin\"\\nTEST!=\"\$$env{LVM_SBIN_PATH}\/lvm\", ENV{LVM_SBIN_PATH}=\"\/usr\/sbin\"
+LVM_EXEC=\$$env{LVM_SBIN_PATH}
+else
+SBIN="@sbindir@"
+DM_EXEC_RULE=""
+DM_EXEC=${SBIN}
+LVM_EXEC_RULE=""
+LVM_EXEC=${SBIN}
+endif
+
+ifeq ("@UDEV_HAS_BUILTIN_BLKID@", "yes")
+BLKID_RULE=IMPORT{builtin}=\"blkid\"
+else
+BLKID_RULE=IMPORT{program}=\"${SBIN}\/blkid -o udev -p \$$tempnode\"
+endif
 
 %.rules: %.rules.in
-       $(SED) -e "s/(DM_DIR)/$(DM_DIR)/" $< >$@
+       $(SED) -e "s+(DM_DIR)+$(DM_DIR)+;s+(BLKID_RULE)+$(BLKID_RULE)+;s+(DM_EXEC_RULE)+$(DM_EXEC_RULE)+;s+(DM_EXEC)+$(DM_EXEC)+;s+(LVM_EXEC_RULE)+$(LVM_EXEC_RULE)+;s+(LVM_EXEC)+$(LVM_EXEC)+;" $< >$@
 
 %_install: %.rules
        $(INSTALL_DATA) -D $< $(udevdir)/$(<F)
index b430a9c1b5b721e2a05cb163b2c04f239a6acecd..704f1168e780576acb98e3d5c21fd77a2f47f210 100644 (file)
@@ -158,11 +158,9 @@ static void check_object_growth()
 {
        int i;
        struct dm_pool *p = dm_pool_create("", 32);
-       char data[100];
+       char data[100] = { 0 };
        void *obj;
 
-       memset(data, 0, sizeof(data));
-
        dm_pool_begin_object(p, 43);
        for (i = 1; i < 100; i++)
                dm_pool_grow_object(p, data, i);